Add option to provide signature for a token to verify key ownership (#14054)

* Add option to provide signed token to verify key ownership

Currently we will only allow a key to be matched to a user if it matches
an activated email address. This PR provides a different mechanism - if
the user provides a signature for automatically generated token (based
on the timestamp, user creation time, user ID, username and primary
email.

* Ensure verified keys can act for all active emails for the user

* Add code to mark keys as verified

* Slight UI adjustments

* Slight UI adjustments 2

* Simplify signature verification slightly

* fix postgres test

* add api routes

* handle swapped primary-keys

* Verify the no-reply address for verified keys

* Only add email addresses that are activated to keys

* Fix committer shortcut properly

* Restructure gpg_keys.go

* Use common Verification Token code

Signed-off-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
zeripath 2021-07-13 14:28:07 +01:00 committed by GitHub
parent 67f135ca5d
commit b82293270c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 1276 additions and 727 deletions

View file

@ -29,10 +29,10 @@ func TestGPGKeys(t *testing.T) {
results []int
}{
{name: "NoLogin", makeRequest: MakeRequest, token: "",
results: []int{http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized},
results: []int{http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized},
},
{name: "LoggedAsUser2", makeRequest: session.MakeRequest, token: token,
results: []int{http.StatusOK, http.StatusOK, http.StatusNotFound, http.StatusNoContent, http.StatusUnprocessableEntity, http.StatusNotFound, http.StatusCreated, http.StatusCreated}},
results: []int{http.StatusOK, http.StatusOK, http.StatusNotFound, http.StatusNoContent, http.StatusUnprocessableEntity, http.StatusNotFound, http.StatusCreated, http.StatusNotFound, http.StatusCreated}},
}
for _, tc := range tt {
@ -60,7 +60,7 @@ func TestGPGKeys(t *testing.T) {
t.Run("CreateValidGPGKey", func(t *testing.T) {
testCreateValidGPGKey(t, tc.makeRequest, tc.token, tc.results[6])
})
t.Run("CreateValidSecondaryEmailGPGKey", func(t *testing.T) {
t.Run("CreateValidSecondaryEmailGPGKeyNotActivated", func(t *testing.T) {
testCreateValidSecondaryEmailGPGKey(t, tc.makeRequest, tc.token, tc.results[7])
})
})
@ -74,6 +74,7 @@ func TestGPGKeys(t *testing.T) {
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys?token="+token) //GET all keys
resp := session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &keys)
assert.Len(t, keys, 1)
primaryKey1 := keys[0] //Primary key 1
assert.EqualValues(t, "38EA3BCED732982C", primaryKey1.KeyID)
@ -85,12 +86,6 @@ func TestGPGKeys(t *testing.T) {
assert.EqualValues(t, "70D7C694D17D03AD", subKey.KeyID)
assert.Empty(t, subKey.Emails)
primaryKey2 := keys[1] //Primary key 2
assert.EqualValues(t, "3CEF46EF40BEFC3E", primaryKey2.KeyID)
assert.Len(t, primaryKey2.Emails, 1)
assert.EqualValues(t, "user2-2@example.com", primaryKey2.Emails[0].Email)
assert.False(t, primaryKey2.Emails[0].Verified)
var key api.GPGKey
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey1.ID, 10)+"?token="+token) //Primary key 1
resp = session.MakeRequest(t, req, http.StatusOK)
@ -105,15 +100,6 @@ func TestGPGKeys(t *testing.T) {
DecodeJSON(t, resp, &key)
assert.EqualValues(t, "70D7C694D17D03AD", key.KeyID)
assert.Empty(t, key.Emails)
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey2.ID, 10)+"?token="+token) //Primary key 2
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &key)
assert.EqualValues(t, "3CEF46EF40BEFC3E", key.KeyID)
assert.Len(t, key.Emails, 1)
assert.EqualValues(t, "user2-2@example.com", key.Emails[0].Email)
assert.False(t, key.Emails[0].Verified)
})
//Check state after basic add