2017-09-05 16:45:18 +03:00
// Copyright 2017 The Gogs Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2017-09-05 16:45:18 +03:00
2022-09-02 22:18:23 +03:00
package integration
2017-09-05 16:45:18 +03:00
import (
"net/http"
2017-12-04 01:46:01 +03:00
"net/http/httptest"
2017-09-05 16:45:18 +03:00
"strconv"
"testing"
2023-01-18 00:46:03 +03:00
auth_model "code.gitea.io/gitea/models/auth"
2019-05-11 13:21:34 +03:00
api "code.gitea.io/gitea/modules/structs"
2022-09-02 22:18:23 +03:00
"code.gitea.io/gitea/tests"
2017-12-04 01:46:01 +03:00
"github.com/stretchr/testify/assert"
2017-09-05 16:45:18 +03:00
)
2017-12-04 01:46:01 +03:00
type makeRequestFunc func ( testing . TB , * http . Request , int ) * httptest . ResponseRecorder
2017-09-05 16:45:18 +03:00
func TestGPGKeys ( t * testing . T ) {
2022-09-02 22:18:23 +03:00
defer tests . PrepareTestEnv ( t ) ( )
2017-09-05 16:45:18 +03:00
session := loginUser ( t , "user2" )
Redesign Scoped Access Tokens (#24767)
## Changes
- Adds the following high level access scopes, each with `read` and
`write` levels:
- `activitypub`
- `admin` (hidden if user is not a site admin)
- `misc`
- `notification`
- `organization`
- `package`
- `issue`
- `repository`
- `user`
- Adds new middleware function `tokenRequiresScopes()` in addition to
`reqToken()`
- `tokenRequiresScopes()` is used for each high-level api section
- _if_ a scoped token is present, checks that the required scope is
included based on the section and HTTP method
- `reqToken()` is used for individual routes
- checks that required authentication is present (but does not check
scope levels as this will already have been handled by
`tokenRequiresScopes()`
- Adds migration to convert old scoped access tokens to the new set of
scopes
- Updates the user interface for scope selection
### User interface example
<img width="903" alt="Screen Shot 2023-05-31 at 1 56 55 PM"
src="https://github.com/go-gitea/gitea/assets/23248839/654766ec-2143-4f59-9037-3b51600e32f3">
<img width="917" alt="Screen Shot 2023-05-31 at 1 56 43 PM"
src="https://github.com/go-gitea/gitea/assets/23248839/1ad64081-012c-4a73-b393-66b30352654c">
## tokenRequiresScopes Design Decision
- `tokenRequiresScopes()` was added to more reliably cover api routes.
For an incoming request, this function uses the given scope category
(say `AccessTokenScopeCategoryOrganization`) and the HTTP method (say
`DELETE`) and verifies that any scoped tokens in use include
`delete:organization`.
- `reqToken()` is used to enforce auth for individual routes that
require it. If a scoped token is not present for a request,
`tokenRequiresScopes()` will not return an error
## TODO
- [x] Alphabetize scope categories
- [x] Change 'public repos only' to a radio button (private vs public).
Also expand this to organizations
- [X] Disable token creation if no scopes selected. Alternatively, show
warning
- [x] `reqToken()` is missing from many `POST/DELETE` routes in the api.
`tokenRequiresScopes()` only checks that a given token has the correct
scope, `reqToken()` must be used to check that a token (or some other
auth) is present.
- _This should be addressed in this PR_
- [x] The migration should be reviewed very carefully in order to
minimize access changes to existing user tokens.
- _This should be addressed in this PR_
- [x] Link to api to swagger documentation, clarify what
read/write/delete levels correspond to
- [x] Review cases where more than one scope is needed as this directly
deviates from the api definition.
- _This should be addressed in this PR_
- For example:
```go
m.Group("/users/{username}/orgs", func() {
m.Get("", reqToken(), org.ListUserOrgs)
m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser,
auth_model.AccessTokenScopeCategoryOrganization),
context_service.UserAssignmentAPI())
```
## Future improvements
- [ ] Add required scopes to swagger documentation
- [ ] Redesign `reqToken()` to be opt-out rather than opt-in
- [ ] Subdivide scopes like `repository`
- [ ] Once a token is created, if it has no scopes, we should display
text instead of an empty bullet point
- [ ] If the 'public repos only' option is selected, should read
categories be selected by default
Closes #24501
Closes #24799
Co-authored-by: Jonathan Tran <jon@allspice.io>
Co-authored-by: Kyle D <kdumontnu@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
2023-06-04 21:57:16 +03:00
token := getTokenForLoggedInUser ( t , session , auth_model . AccessTokenScopeWriteRepository )
tokenWithGPGKeyScope := getTokenForLoggedInUser ( t , session , auth_model . AccessTokenScopeWriteRepository , auth_model . AccessTokenScopeWriteUser )
2017-09-05 16:45:18 +03:00
tt := [ ] struct {
2017-12-04 01:46:01 +03:00
name string
makeRequest makeRequestFunc
2018-09-10 19:15:52 +03:00
token string
2017-12-04 01:46:01 +03:00
results [ ] int
2017-09-05 16:45:18 +03:00
} {
2022-01-20 20:46:10 +03:00
{
name : "NoLogin" , makeRequest : MakeRequest , token : "" ,
2021-07-13 16:28:07 +03:00
results : [ ] int { http . StatusUnauthorized , http . StatusUnauthorized , http . StatusUnauthorized , http . StatusUnauthorized , http . StatusUnauthorized , http . StatusUnauthorized , http . StatusUnauthorized , http . StatusUnauthorized , http . StatusUnauthorized } ,
2017-09-05 16:45:18 +03:00
} ,
2022-01-20 20:46:10 +03:00
{
name : "LoggedAsUser2" , makeRequest : session . MakeRequest , token : token ,
Redesign Scoped Access Tokens (#24767)
## Changes
- Adds the following high level access scopes, each with `read` and
`write` levels:
- `activitypub`
- `admin` (hidden if user is not a site admin)
- `misc`
- `notification`
- `organization`
- `package`
- `issue`
- `repository`
- `user`
- Adds new middleware function `tokenRequiresScopes()` in addition to
`reqToken()`
- `tokenRequiresScopes()` is used for each high-level api section
- _if_ a scoped token is present, checks that the required scope is
included based on the section and HTTP method
- `reqToken()` is used for individual routes
- checks that required authentication is present (but does not check
scope levels as this will already have been handled by
`tokenRequiresScopes()`
- Adds migration to convert old scoped access tokens to the new set of
scopes
- Updates the user interface for scope selection
### User interface example
<img width="903" alt="Screen Shot 2023-05-31 at 1 56 55 PM"
src="https://github.com/go-gitea/gitea/assets/23248839/654766ec-2143-4f59-9037-3b51600e32f3">
<img width="917" alt="Screen Shot 2023-05-31 at 1 56 43 PM"
src="https://github.com/go-gitea/gitea/assets/23248839/1ad64081-012c-4a73-b393-66b30352654c">
## tokenRequiresScopes Design Decision
- `tokenRequiresScopes()` was added to more reliably cover api routes.
For an incoming request, this function uses the given scope category
(say `AccessTokenScopeCategoryOrganization`) and the HTTP method (say
`DELETE`) and verifies that any scoped tokens in use include
`delete:organization`.
- `reqToken()` is used to enforce auth for individual routes that
require it. If a scoped token is not present for a request,
`tokenRequiresScopes()` will not return an error
## TODO
- [x] Alphabetize scope categories
- [x] Change 'public repos only' to a radio button (private vs public).
Also expand this to organizations
- [X] Disable token creation if no scopes selected. Alternatively, show
warning
- [x] `reqToken()` is missing from many `POST/DELETE` routes in the api.
`tokenRequiresScopes()` only checks that a given token has the correct
scope, `reqToken()` must be used to check that a token (or some other
auth) is present.
- _This should be addressed in this PR_
- [x] The migration should be reviewed very carefully in order to
minimize access changes to existing user tokens.
- _This should be addressed in this PR_
- [x] Link to api to swagger documentation, clarify what
read/write/delete levels correspond to
- [x] Review cases where more than one scope is needed as this directly
deviates from the api definition.
- _This should be addressed in this PR_
- For example:
```go
m.Group("/users/{username}/orgs", func() {
m.Get("", reqToken(), org.ListUserOrgs)
m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser,
auth_model.AccessTokenScopeCategoryOrganization),
context_service.UserAssignmentAPI())
```
## Future improvements
- [ ] Add required scopes to swagger documentation
- [ ] Redesign `reqToken()` to be opt-out rather than opt-in
- [ ] Subdivide scopes like `repository`
- [ ] Once a token is created, if it has no scopes, we should display
text instead of an empty bullet point
- [ ] If the 'public repos only' option is selected, should read
categories be selected by default
Closes #24501
Closes #24799
Co-authored-by: Jonathan Tran <jon@allspice.io>
Co-authored-by: Kyle D <kdumontnu@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
2023-06-04 21:57:16 +03:00
results : [ ] int { http . StatusForbidden , http . StatusForbidden , http . StatusForbidden , http . StatusForbidden , http . StatusForbidden , http . StatusForbidden , http . StatusForbidden , http . StatusForbidden , http . StatusForbidden } ,
2023-01-18 00:46:03 +03:00
} ,
{
name : "LoggedAsUser2WithScope" , makeRequest : session . MakeRequest , token : tokenWithGPGKeyScope ,
2022-01-20 20:46:10 +03:00
results : [ ] int { http . StatusOK , http . StatusOK , http . StatusNotFound , http . StatusNoContent , http . StatusUnprocessableEntity , http . StatusNotFound , http . StatusCreated , http . StatusNotFound , http . StatusCreated } ,
} ,
2017-09-05 16:45:18 +03:00
}
for _ , tc := range tt {
2022-01-20 20:46:10 +03:00
// Basic test on result code
2017-09-05 16:45:18 +03:00
t . Run ( tc . name , func ( t * testing . T ) {
t . Run ( "ViewOwnGPGKeys" , func ( t * testing . T ) {
2018-09-10 19:15:52 +03:00
testViewOwnGPGKeys ( t , tc . makeRequest , tc . token , tc . results [ 0 ] )
2017-09-05 16:45:18 +03:00
} )
t . Run ( "ViewGPGKeys" , func ( t * testing . T ) {
2018-09-10 19:15:52 +03:00
testViewGPGKeys ( t , tc . makeRequest , tc . token , tc . results [ 1 ] )
2017-09-05 16:45:18 +03:00
} )
t . Run ( "GetGPGKey" , func ( t * testing . T ) {
2018-09-10 19:15:52 +03:00
testGetGPGKey ( t , tc . makeRequest , tc . token , tc . results [ 2 ] )
2017-09-05 16:45:18 +03:00
} )
t . Run ( "DeleteGPGKey" , func ( t * testing . T ) {
2018-09-10 19:15:52 +03:00
testDeleteGPGKey ( t , tc . makeRequest , tc . token , tc . results [ 3 ] )
2017-09-05 16:45:18 +03:00
} )
t . Run ( "CreateInvalidGPGKey" , func ( t * testing . T ) {
2018-09-10 19:15:52 +03:00
testCreateInvalidGPGKey ( t , tc . makeRequest , tc . token , tc . results [ 4 ] )
2017-09-05 16:45:18 +03:00
} )
t . Run ( "CreateNoneRegistredEmailGPGKey" , func ( t * testing . T ) {
2018-09-10 19:15:52 +03:00
testCreateNoneRegistredEmailGPGKey ( t , tc . makeRequest , tc . token , tc . results [ 5 ] )
2017-09-05 16:45:18 +03:00
} )
t . Run ( "CreateValidGPGKey" , func ( t * testing . T ) {
2018-09-10 19:15:52 +03:00
testCreateValidGPGKey ( t , tc . makeRequest , tc . token , tc . results [ 6 ] )
2017-09-05 16:45:18 +03:00
} )
2021-07-13 16:28:07 +03:00
t . Run ( "CreateValidSecondaryEmailGPGKeyNotActivated" , func ( t * testing . T ) {
2018-09-10 19:15:52 +03:00
testCreateValidSecondaryEmailGPGKey ( t , tc . makeRequest , tc . token , tc . results [ 7 ] )
2017-09-05 16:45:18 +03:00
} )
} )
}
2022-01-20 20:46:10 +03:00
// Check state after basic add
2017-09-05 16:45:18 +03:00
t . Run ( "CheckState" , func ( t * testing . T ) {
var keys [ ] * api . GPGKey
2023-01-18 00:46:03 +03:00
req := NewRequest ( t , "GET" , "/api/v1/user/gpg_keys?token=" + tokenWithGPGKeyScope ) // GET all keys
2022-12-02 06:39:42 +03:00
resp := MakeRequest ( t , req , http . StatusOK )
2017-09-05 16:45:18 +03:00
DecodeJSON ( t , resp , & keys )
2021-07-13 16:28:07 +03:00
assert . Len ( t , keys , 1 )
2017-09-05 16:45:18 +03:00
2022-01-20 20:46:10 +03:00
primaryKey1 := keys [ 0 ] // Primary key 1
2017-09-05 16:45:18 +03:00
assert . EqualValues ( t , "38EA3BCED732982C" , primaryKey1 . KeyID )
2021-06-07 08:27:09 +03:00
assert . Len ( t , primaryKey1 . Emails , 1 )
2017-09-05 16:45:18 +03:00
assert . EqualValues ( t , "user2@example.com" , primaryKey1 . Emails [ 0 ] . Email )
2021-06-07 08:27:09 +03:00
assert . True ( t , primaryKey1 . Emails [ 0 ] . Verified )
2017-09-05 16:45:18 +03:00
2022-01-20 20:46:10 +03:00
subKey := primaryKey1 . SubsKey [ 0 ] // Subkey of 38EA3BCED732982C
2017-09-05 16:45:18 +03:00
assert . EqualValues ( t , "70D7C694D17D03AD" , subKey . KeyID )
2021-06-07 08:27:09 +03:00
assert . Empty ( t , subKey . Emails )
2017-09-05 16:45:18 +03:00
var key api . GPGKey
2023-01-18 00:46:03 +03:00
req = NewRequest ( t , "GET" , "/api/v1/user/gpg_keys/" + strconv . FormatInt ( primaryKey1 . ID , 10 ) + "?token=" + tokenWithGPGKeyScope ) // Primary key 1
2022-12-02 06:39:42 +03:00
resp = MakeRequest ( t , req , http . StatusOK )
2017-09-05 16:45:18 +03:00
DecodeJSON ( t , resp , & key )
assert . EqualValues ( t , "38EA3BCED732982C" , key . KeyID )
2021-06-07 08:27:09 +03:00
assert . Len ( t , key . Emails , 1 )
2017-09-05 16:45:18 +03:00
assert . EqualValues ( t , "user2@example.com" , key . Emails [ 0 ] . Email )
2021-06-07 08:27:09 +03:00
assert . True ( t , key . Emails [ 0 ] . Verified )
2017-09-05 16:45:18 +03:00
2023-01-18 00:46:03 +03:00
req = NewRequest ( t , "GET" , "/api/v1/user/gpg_keys/" + strconv . FormatInt ( subKey . ID , 10 ) + "?token=" + tokenWithGPGKeyScope ) // Subkey of 38EA3BCED732982C
2022-12-02 06:39:42 +03:00
resp = MakeRequest ( t , req , http . StatusOK )
2017-09-05 16:45:18 +03:00
DecodeJSON ( t , resp , & key )
assert . EqualValues ( t , "70D7C694D17D03AD" , key . KeyID )
2021-06-07 08:27:09 +03:00
assert . Empty ( t , key . Emails )
2017-09-05 16:45:18 +03:00
} )
2022-01-20 20:46:10 +03:00
// Check state after basic add
2017-09-05 16:45:18 +03:00
t . Run ( "CheckCommits" , func ( t * testing . T ) {
t . Run ( "NotSigned" , func ( t * testing . T ) {
var branch api . Branch
2018-09-10 19:15:52 +03:00
req := NewRequest ( t , "GET" , "/api/v1/repos/user2/repo16/branches/not-signed?token=" + token )
2022-12-02 06:39:42 +03:00
resp := MakeRequest ( t , req , http . StatusOK )
2017-09-05 16:45:18 +03:00
DecodeJSON ( t , resp , & branch )
2021-06-07 08:27:09 +03:00
assert . False ( t , branch . Commit . Verification . Verified )
2017-09-05 16:45:18 +03:00
} )
t . Run ( "SignedWithNotValidatedEmail" , func ( t * testing . T ) {
var branch api . Branch
2018-09-10 19:15:52 +03:00
req := NewRequest ( t , "GET" , "/api/v1/repos/user2/repo16/branches/good-sign-not-yet-validated?token=" + token )
2022-12-02 06:39:42 +03:00
resp := MakeRequest ( t , req , http . StatusOK )
2017-09-05 16:45:18 +03:00
DecodeJSON ( t , resp , & branch )
2021-06-07 08:27:09 +03:00
assert . False ( t , branch . Commit . Verification . Verified )
2017-09-05 16:45:18 +03:00
} )
t . Run ( "SignedWithValidEmail" , func ( t * testing . T ) {
var branch api . Branch
2018-09-10 19:15:52 +03:00
req := NewRequest ( t , "GET" , "/api/v1/repos/user2/repo16/branches/good-sign?token=" + token )
2022-12-02 06:39:42 +03:00
resp := MakeRequest ( t , req , http . StatusOK )
2017-09-05 16:45:18 +03:00
DecodeJSON ( t , resp , & branch )
2021-06-07 08:27:09 +03:00
assert . True ( t , branch . Commit . Verification . Verified )
2017-09-05 16:45:18 +03:00
} )
} )
}
2018-09-10 19:15:52 +03:00
func testViewOwnGPGKeys ( t * testing . T , makeRequest makeRequestFunc , token string , expected int ) {
req := NewRequest ( t , "GET" , "/api/v1/user/gpg_keys?token=" + token )
2017-12-04 01:46:01 +03:00
makeRequest ( t , req , expected )
2017-09-05 16:45:18 +03:00
}
2018-09-10 19:15:52 +03:00
func testViewGPGKeys ( t * testing . T , makeRequest makeRequestFunc , token string , expected int ) {
req := NewRequest ( t , "GET" , "/api/v1/users/user2/gpg_keys?token=" + token )
2017-12-04 01:46:01 +03:00
makeRequest ( t , req , expected )
2017-09-05 16:45:18 +03:00
}
2018-09-10 19:15:52 +03:00
func testGetGPGKey ( t * testing . T , makeRequest makeRequestFunc , token string , expected int ) {
req := NewRequest ( t , "GET" , "/api/v1/user/gpg_keys/1?token=" + token )
2017-12-04 01:46:01 +03:00
makeRequest ( t , req , expected )
2017-09-05 16:45:18 +03:00
}
2018-09-10 19:15:52 +03:00
func testDeleteGPGKey ( t * testing . T , makeRequest makeRequestFunc , token string , expected int ) {
req := NewRequest ( t , "DELETE" , "/api/v1/user/gpg_keys/1?token=" + token )
2017-12-04 01:46:01 +03:00
makeRequest ( t , req , expected )
2017-09-05 16:45:18 +03:00
}
2018-09-10 19:15:52 +03:00
func testCreateGPGKey ( t * testing . T , makeRequest makeRequestFunc , token string , expected int , publicKey string ) {
req := NewRequestWithJSON ( t , "POST" , "/api/v1/user/gpg_keys?token=" + token , api . CreateGPGKeyOption {
2017-09-05 16:45:18 +03:00
ArmoredKey : publicKey ,
} )
2017-12-04 01:46:01 +03:00
makeRequest ( t , req , expected )
2017-09-05 16:45:18 +03:00
}
2018-09-10 19:15:52 +03:00
func testCreateInvalidGPGKey ( t * testing . T , makeRequest makeRequestFunc , token string , expected int ) {
testCreateGPGKey ( t , makeRequest , token , expected , "invalid_key" )
2017-09-05 16:45:18 +03:00
}
2018-09-10 19:15:52 +03:00
func testCreateNoneRegistredEmailGPGKey ( t * testing . T , makeRequest makeRequestFunc , token string , expected int ) {
testCreateGPGKey ( t , makeRequest , token , expected , ` -- -- - BEGIN PGP PUBLIC KEY BLOCK -- -- -
2017-09-05 16:45:18 +03:00
mQENBFmGUygBCACjCNbKvMGgp0fd5vyFW9olE1CLCSyyF9gQN2hSuzmZLuAZF2Kh
dCMCG2T1UwzUB / yWUFWJ2BtCwSjuaRv + cGohqEy6bhEBV90peGA33lHfjx7wP25O
7 moAphDOTZtDj1AZfCh / PTcJut8Lc0eRDMhNyp / bYtO7SHNT1Hr6rrCV / xEtSAvR
3 b148 / tmIBiSadaLwc558KU3ucjnW5RVGins3AjBZ + TuT4XXVH / oeLSeXPSJ5rt1
rHwaseslMqZ4AbvwFLx5qn1OC9rEQv / F548QsA8m0IntLjoPon + 6 wcubA9Gra21c
Fp6aRYl9x7fiqXDLg8i3s2nKdV7 + e6as6Tp9ABEBAAG0FG5vdGtub3duQGV4YW1w
bGUuY29tiQEcBBABAgAGBQJZhlMoAAoJEC8 + pvYULDtte / wH / 2 JNrhmHwDY + hMj0
batIK4HICnkKxjIgbha80P2Ao08NkzSge58fsxiKDFYAQjHui + ZAw4dq79Ax9AOO
Iv2GS9 + DUfWhrb6RF + vNuJldFzcI0rTW / z2q + XGKrUCwN3khJY5XngHfQQrdBtMK
qsoUXz / 5 B8g422RTbo / SdPsyYAV6HeLLeV3rdgjI1fpaW0seZKHeTXQb / HvNeuPg
qz + XV1g6Gdqa1RjDOaX7A8elVKxrYq3LBtc93FW + grBde8n7JL0zPM3DY + vJ0IJZ
INx / MmBfmtCq05FqNclvU + sj2R3N1JJOtBOjZrJHQbJhzoILou8AkxeX1A + q9OAz
1 geiY5E =
= TkP3
-- -- - END PGP PUBLIC KEY BLOCK -- -- - ` )
}
2018-09-10 19:15:52 +03:00
func testCreateValidGPGKey ( t * testing . T , makeRequest makeRequestFunc , token string , expected int ) {
2022-01-20 20:46:10 +03:00
// User2 <user2@example.com> //primary & activated
2018-09-10 19:15:52 +03:00
testCreateGPGKey ( t , makeRequest , token , expected , ` -- -- - BEGIN PGP PUBLIC KEY BLOCK -- -- -
2017-09-05 16:45:18 +03:00
mQENBFmGVsMBCACuxgZ7W7rI9xN08Y4M7B8yx / 6 / I4Slm94 + wXf8YNRvAyqj30dW
VJhyBcnfNRDLKSQp5o / hhfDkCgdqBjLa1PnHlGS3PXJc0hP / FyYPD2BFvNMPpCYS
eu3T1qKSNXm6X0XOWD2LIrdiDC8HaI9FqZVMI / srMK2CF8XCL2m67W1FuoPlWzod
5 ORy0IZB7spoF0xihmcgnEGElRmdo5w / vkGH8U7Zyn9Eb57UVFeafgeskf4wqB23
BjbMdW2YaB + yzMRwYgOnD5lnBD4uqSmvjaV9C0kxn7x + oJkkiRV8 / z1cNcO + BaeQ
Akh / yTTeTzYGSc / ZOqCX1O + NOPgSeixVlqenABEBAAG0GVVzZXIyIDx1c2VyMkBl
eGFtcGxlLmNvbT6JAVQEEwEIAD4WIQRXgbSh0TtGbgRd7XI46jvO1zKYLAUCWYZW
wwIbAwUJA8JnAAULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRA46jvO1zKYLF / e
B / 91 wm2KLMIQBZBA9WA2 / + 9 rQWTo9EqgYrXN60rEzX3cYJWXZiE4DrKR1oWDGNLi
KXOCW62snvJldolBqq0ZqaKvPKzl0Y5TRqbYEc9AjUSqgRin1b + G2DevLGT4ibq +
7 ocQvz0XkASEUAgHahp0Ubiiib1521WwT / duL + AG8Gg0 + DK09RfV3eX5 / EOkQCKv
8 cutqgsd2Smz40A8wXuJkRcipZBtrB / GkUaZ / eJdwEeSYZjEA9GWF61LJT2stvRN
HCk7C3z3pVEek1PluiFs / 4 VN8BG8yDzW4c0tLty4Fj3VwPqwIbB5AJbquVfhQCb4
Eep2lm3Lc9b1OwO5N3coPJkouQENBFmGVsMBCADAGba2L6NCOE1i3WIP6CPzbdOo
N3gdTfTgccAx9fNeon9jor + 3 tgEjlo9 / 6 cXiRoksOV6W4wFab / ZwWgwN6JO4CGvZ
Wi7EQwMMMp1E36YTojKQJrcA9UvMnTHulqQQ88F5E845DhzFQM3erv42QZZMBAX3
kXCgy1GNFocl6tLUvJdEqs + VcJGGANMpmzE4WLa8KhSYnxipwuQ62JBy9R + cHyKT
OARk8znRqSu5bT3LtlrZ / HXu + 6 Oy4 + 2 uCdNzZIh5J5tPS7CPA6ptl88iGVBte / CJ
7 cjgJWSQqeYp2Y5QvsWAivkQ4Ww9plHbbwV0A2eaHsjjWzlUl3HoJ / snMOhBABEB
AAGJATwEGAEIACYWIQRXgbSh0TtGbgRd7XI46jvO1zKYLAUCWYZWwwIbDAUJA8Jn
AAAKCRA46jvO1zKYLBwLCACQOpeRVrwIKVaWcPMYjVHHJsGscaLKpgpARAUgbiG6
Cbc2WI8Sm3fRwrY0VAfN + u9QwrtvxANcyB3vTgTzw7FimfhOimxiTSO8HQCfjDZF
Xly8rq + Fua7 + ClWUpy21IekW41VvZYjH2sL6EVP + UcEOaGAyN53XfhaRVZPhNtZN
NKAE9N5EG3rbsZ33LzJj40rEKlzFSseAAPft8qA3IXjzFBx + PQXHMpNCagL79he6
lqockTJ + oPmta4CF / J0U5LUr1tOZXheL3TP6m8d08gDrtn0YuGOPk87i9sJz + jR9
uy6MA3VSB99SK9ducGmE1Jv8mcziREroz2TEGr0zPs6h
= J59D
-- -- - END PGP PUBLIC KEY BLOCK -- -- - ` )
}
2018-09-10 19:15:52 +03:00
func testCreateValidSecondaryEmailGPGKey ( t * testing . T , makeRequest makeRequestFunc , token string , expected int ) {
2022-01-20 20:46:10 +03:00
// User2 <user2-2@example.com> //secondary and not activated
2018-09-10 19:15:52 +03:00
testCreateGPGKey ( t , makeRequest , token , expected , ` -- -- - BEGIN PGP PUBLIC KEY BLOCK -- -- -
2017-09-05 16:45:18 +03:00
2021-06-08 06:52:51 +03:00
mQGNBGC2K2cBDAC1 + Xgk + 8 UfhASVgRngQi4rnQ8k0t + bWsBz4Czd26 + cxVDRwlTT
8 PALdrbrY / e9iXjcVcZ8Npo4UYe7 / LfnL57dc7tgbenRGYYrWyVoNNv58BVw4xCY
RmgvdHWIIPGuz3aME0smHxbJ2KewYTqjTPuVKF / wrHTwCpVWdjYKC5KDo3yx0mro
xf9vOJOnkWNMiEw7TiZfkrbUqxyA53BVsSNKRX5C3b4FJcVT7eiAq7sDAaFxjEHy
ahZslmvg7XZxWzSVzxDNesR7f4xuop8HBjzaluJoVuwiyWculTvz1b6hyHVQr + ad
h8JGjj1tySI65OTFsTuptsfHXjtjl / NR4P6BXkf + FVwweaTQaEzpHkv0m9b9pY43
CY / 8 XtS4uNPermiLG / Z0BB1eOCdoOQVHpjOa55IXQWhxXB6NZVyowiUbrR7jLDQy
5 JP7D1HmErTR8JRm3VDqGbSaCgugRgFX + lb / fpgFp9k02OeK + JQudolZOt1mVk + T
C4xmEWxfiH15 / JMAEQEAAbQbdXNlcjIgPHVzZXIyLTJAZXhhbXBsZS5jb20 + iQHU
BBMBCAA + FiEEB / Y4DM3Ba2H9iXmlPO9G70C + / D4FAmC2K2cCGwMFCQPCZwAFCwkI
BwIGFQoJCAsCBBYCAwECHgECF4AACgkQPO9G70C + / D59 / Av / XZIhCH4X2FpxCO3d
oCa + sbYkBL5xeUoPfAx5ThXzqL / tllO88TKTMEGZF3k5pocXWH0xmhqlvDTcdb0i
W3O0CN8FLmuotU51c0JC1mt9zwJP9PeJNyqxrMm01Yzj55z / Dz3QHSTlDjrWTWjn
YBqDf2HfdM177oydfSYmevZni1aDmBalWpFPRvqISCO7uFnvg1hJQ5mD / 0 qie663
QJ8LAAANg32H9DyPnYi9wU62WX0DMUVTjKctT3cnYCbirjjJ7ZlCCm + cf61CRX1B
E1Ng / Ef3ZcUfXWitZSjfET / pKEMSNjsQawFpZ / LPCBl + UPHzaTPAASeGJvcbZ3py
wZQLQc1MCu2hmMBQ8zHQTdS2Pp0RISxCQLYvVQL6DrcJDNiSqn9p9RQt5c5r5Pjx
80 BIPcjj3glOVP7PYE2azQAkt6reEjhimwCfjeDpiPnkBTY7Av2jCcUFhhemDY / j
TRXK1paLphhJ36zC22SeHGxNNakjjuUakqB85DEUeoWuVm6ouQGNBGC2K2cBDADx
G2rIAgMjdPtofhkEZXwv6zdNwmYOlIIM + 59 bam9Ep / vFq8F5f + xldevm5dvM8SeR
pNwDGSOUf5OKBWBdsJFhlYBl7 + EcKd / Tent / XS6JoA9ffF33b + r04L543 + ykiKON
WYeYi0F4WwYTIQgqZHJze1sPVkYGR5F0bL8PAcLuwd5dzZVi / q2HakrGdg29N8oY
b / XnoR7FflPrNYdzO6hawi5Inx7KS7aWa0ZkARb0F4HSct + / m6nAZVsoJINLudyQ
ut2NWeU8rWIm1hqyIxQFvuQJy46umq ++ 10 J / sWA98bkg41Rx + 72 + eP7DM5v8IgUp
clJsfljRXIBWbmRAVZvtNI7PX9fwMMhf4M7wHO7G2WV39o1exKps5xFFcn8PUQiX
jCSR81M145CgCdmLUR1y0pdkN / WIqjXBhkPIvO2dxEcodMNHb1aUUuUOnww6 + xIP
8 rGVw + a2DUiALc8Qr5RP21AYKRctfiwhSQh2KODveMtyLI3U9C / eLRPp + QM3XB8A
EQEAAYkBvAQYAQgAJhYhBAf2OAzNwWth / Yl5pTzvRu9Avvw + BQJgtitnAhsMBQkD
wmcAAAoJEDzvRu9Avvw + 3 FcMAJBwupyJ4zwQFxTJ5BkDlusG3U2FXEf3bDrXhvNd
qi8eS8Vo / vRiH / w / my5JFpz1o2tJToryF71D + uF5DTItalKquhsQ9reAEmXggqOh
9 Jd9mWJIEEWcRORiLNDKENKvE8bouw4U4hRaSF0IaGzAe5mO + oOvwal8L97wFxrZ
4 leM1GzkopiuNfbkkBBw2KJcMjYBHzzXSCALnVwhjbgkBEWPIg38APT3cr9KfnMM
q8 + tvsGLj4piAl3Lww7 + GhSsDOUXH8btR41BSAQDrbO5q6oi / h4nuxoNmQIDW / Ug
s + dd5hnY2FtHRjb4FCR9kAjdTE6stc8wzohWfbg1N + 12 TTA2ylByAumICVXixavH
RJ7l0OiWJk388qw9mqh3k8HcBxL7OfDlFC9oPmCS0iYiIwW / Yc80kBhoxcvl / Xa7
mIMMn8taHIaQO7v9ln2EVQYTzbNCmwTw9ovTM0j / Pbkg2EftfP1TCoxQHvBnsCED
6 qgtsUdi5eviONRkBgeZtN3oxA ==
= MgDv
2017-09-05 16:45:18 +03:00
-- -- - END PGP PUBLIC KEY BLOCK -- -- - ` )
}