Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
cb47d5f0
Commit
cb47d5f0
authored
Dec 03, 2020
by
κeen
Committed by
Nick Thomas
Dec 03, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add an URL to get user's GPG key
parent
eb5aa2ee
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
332 additions
and
1 deletion
+332
-1
app/controllers/profiles/gpg_keys_controller.rb
app/controllers/profiles/gpg_keys_controller.rb
+19
-0
changelogs/unreleased/gpg-keys-publicly-accessible.yml
changelogs/unreleased/gpg-keys-publicly-accessible.yml
+5
-0
config/routes/user.rb
config/routes/user.rb
+4
-1
spec/controllers/profiles/gpg_keys_controller_spec.rb
spec/controllers/profiles/gpg_keys_controller_spec.rb
+136
-0
spec/factories/gpg_keys.rb
spec/factories/gpg_keys.rb
+5
-0
spec/routing/routing_spec.rb
spec/routing/routing_spec.rb
+24
-0
spec/support/helpers/gpg_helpers.rb
spec/support/helpers/gpg_helpers.rb
+139
-0
No files found.
app/controllers/profiles/gpg_keys_controller.rb
View file @
cb47d5f0
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
class
Profiles::GpgKeysController
<
Profiles
::
ApplicationController
class
Profiles::GpgKeysController
<
Profiles
::
ApplicationController
before_action
:set_gpg_key
,
only:
[
:destroy
,
:revoke
]
before_action
:set_gpg_key
,
only:
[
:destroy
,
:revoke
]
skip_before_action
:authenticate_user!
,
only:
[
:get_keys
]
feature_category
:users
feature_category
:users
...
@@ -39,6 +40,24 @@ class Profiles::GpgKeysController < Profiles::ApplicationController
...
@@ -39,6 +40,24 @@ class Profiles::GpgKeysController < Profiles::ApplicationController
end
end
end
end
# Get all gpg keys of a user(params[:username]) in a text format
def
get_keys
if
params
[
:username
].
present?
begin
user
=
UserFinder
.
new
(
params
[
:username
]).
find_by_username
if
user
.
present?
render
plain:
user
.
gpg_keys
.
select
(
&
:verified?
).
map
(
&
:key
).
join
(
"
\n
"
)
else
render_404
end
rescue
=>
e
render
html:
e
.
message
end
else
render_404
end
end
private
private
def
gpg_key_params
def
gpg_key_params
...
...
changelogs/unreleased/gpg-keys-publicly-accessible.yml
0 → 100644
View file @
cb47d5f0
---
title
:
Add an URL to get user's GPG key if registerd
merge_request
:
48321
author
:
Shimura Rin @blackenedgold
type
:
added
config/routes/user.rb
View file @
cb47d5f0
...
@@ -54,9 +54,12 @@ scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) d
...
@@ -54,9 +54,12 @@ scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) d
end
end
constraints
(
::
Constraints
::
UserUrlConstrainer
.
new
)
do
constraints
(
::
Constraints
::
UserUrlConstrainer
.
new
)
do
# Get all keys of user
# Get all
SSH
keys of user
get
':username.keys'
=>
'profiles/keys#get_keys'
,
constraints:
{
username:
Gitlab
::
PathRegex
.
root_namespace_route_regex
}
get
':username.keys'
=>
'profiles/keys#get_keys'
,
constraints:
{
username:
Gitlab
::
PathRegex
.
root_namespace_route_regex
}
# Get all GPG keys of user
get
':username.gpg'
=>
'profiles/gpg_keys#get_keys'
,
constraints:
{
username:
Gitlab
::
PathRegex
.
root_namespace_route_regex
}
scope
(
path:
':username'
,
scope
(
path:
':username'
,
as: :user
,
as: :user
,
constraints:
{
username:
Gitlab
::
PathRegex
.
root_namespace_route_regex
},
constraints:
{
username:
Gitlab
::
PathRegex
.
root_namespace_route_regex
},
...
...
spec/controllers/profiles/gpg_keys_controller_spec.rb
0 → 100644
View file @
cb47d5f0
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Profiles
::
GpgKeysController
do
let
(
:user
)
{
create
(
:user
,
email:
GpgHelpers
::
User1
.
emails
[
0
])
}
describe
'POST #create'
do
before
do
sign_in
(
user
)
end
it
'creates a new key'
do
expect
do
post
:create
,
params:
{
gpg_key:
build
(
:gpg_key
).
attributes
}
end
.
to
change
{
GpgKey
.
count
}.
by
(
1
)
end
end
describe
"#get_keys"
do
describe
"non existent user"
do
it
"does not generally work"
do
get
:get_keys
,
params:
{
username:
'not-existent'
}
expect
(
response
).
not_to
be_successful
end
end
describe
"user with no keys"
do
it
"does generally work"
do
get
:get_keys
,
params:
{
username:
user
.
username
}
expect
(
response
).
to
be_successful
end
it
"renders all keys separated with a new line"
do
get
:get_keys
,
params:
{
username:
user
.
username
}
expect
(
response
.
body
).
to
eq
(
""
)
end
it
"responds with text/plain content type"
do
get
:get_keys
,
params:
{
username:
user
.
username
}
expect
(
response
.
content_type
).
to
eq
(
"text/plain"
)
end
end
describe
"user with keys"
do
let!
(
:gpg_key
)
{
create
(
:gpg_key
,
user:
user
)
}
let!
(
:another_gpg_key
)
{
create
(
:another_gpg_key
,
user:
user
)
}
describe
"while signed in"
do
before
do
sign_in
(
user
)
end
it
"does generally work"
do
get
:get_keys
,
params:
{
username:
user
.
username
}
expect
(
response
).
to
be_successful
end
it
"renders all verified keys separated with a new line"
do
get
:get_keys
,
params:
{
username:
user
.
username
}
expect
(
response
.
body
).
not_to
eq
(
''
)
expect
(
response
.
body
).
to
eq
(
user
.
gpg_keys
.
select
(
&
:verified?
).
map
(
&
:key
).
join
(
"
\n
"
))
expect
(
response
.
body
).
to
include
(
gpg_key
.
key
)
expect
(
response
.
body
).
to
include
(
another_gpg_key
.
key
)
end
it
"responds with text/plain content type"
do
get
:get_keys
,
params:
{
username:
user
.
username
}
expect
(
response
.
content_type
).
to
eq
(
"text/plain"
)
end
end
describe
'when logged out'
do
before
do
sign_out
(
user
)
end
it
"still does generally work"
do
get
:get_keys
,
params:
{
username:
user
.
username
}
expect
(
response
).
to
be_successful
end
it
"renders all verified keys separated with a new line"
do
get
:get_keys
,
params:
{
username:
user
.
username
}
expect
(
response
.
body
).
not_to
eq
(
''
)
expect
(
response
.
body
).
to
eq
(
user
.
gpg_keys
.
map
(
&
:key
).
join
(
"
\n
"
))
expect
(
response
.
body
).
to
include
(
gpg_key
.
key
)
expect
(
response
.
body
).
to
include
(
another_gpg_key
.
key
)
end
it
"responds with text/plain content type"
do
get
:get_keys
,
params:
{
username:
user
.
username
}
expect
(
response
.
content_type
).
to
eq
(
"text/plain"
)
end
end
describe
'when revoked'
do
before
do
sign_in
(
user
)
another_gpg_key
.
revoke
end
it
"doesn't render revoked keys"
do
get
:get_keys
,
params:
{
username:
user
.
username
}
expect
(
response
.
body
).
not_to
eq
(
''
)
expect
(
response
.
body
).
to
include
(
gpg_key
.
key
)
expect
(
response
.
body
).
not_to
include
(
another_gpg_key
.
key
)
end
it
"doesn't render revoked keys for non-authorized users"
do
sign_out
(
user
)
get
:get_keys
,
params:
{
username:
user
.
username
}
expect
(
response
.
body
).
not_to
eq
(
''
)
expect
(
response
.
body
).
to
include
(
gpg_key
.
key
)
expect
(
response
.
body
).
not_to
include
(
another_gpg_key
.
key
)
end
end
end
end
end
spec/factories/gpg_keys.rb
View file @
cb47d5f0
...
@@ -10,5 +10,10 @@ FactoryBot.define do
...
@@ -10,5 +10,10 @@ FactoryBot.define do
factory
:gpg_key_with_subkeys
do
factory
:gpg_key_with_subkeys
do
key
{
GpgHelpers
::
User1
.
public_key_with_extra_signing_key
}
key
{
GpgHelpers
::
User1
.
public_key_with_extra_signing_key
}
end
end
factory
:another_gpg_key
do
key
{
GpgHelpers
::
User1
.
public_key2
}
user
end
end
end
end
end
spec/routing/routing_spec.rb
View file @
cb47d5f0
...
@@ -183,6 +183,30 @@ RSpec.describe Profiles::KeysController, "routing" do
...
@@ -183,6 +183,30 @@ RSpec.describe Profiles::KeysController, "routing" do
end
end
end
end
# keys GET /gpg_keys gpg_keys#index
# key POST /gpg_keys gpg_keys#create
# PUT /gpg_keys/:id gpg_keys#revoke
# DELETE /gpg_keys/:id gpg_keys#desroy
RSpec
.
describe
Profiles
::
GpgKeysController
,
"routing"
do
it
"to #index"
do
expect
(
get
(
"/profile/gpg_keys"
)).
to
route_to
(
'profiles/gpg_keys#index'
)
end
it
"to #create"
do
expect
(
post
(
"/profile/gpg_keys"
)).
to
route_to
(
'profiles/gpg_keys#create'
)
end
it
"to #destroy"
do
expect
(
delete
(
"/profile/gpg_keys/1"
)).
to
route_to
(
'profiles/gpg_keys#destroy'
,
id:
'1'
)
end
it
"to #get_keys"
do
allow_any_instance_of
(
::
Constraints
::
UserUrlConstrainer
).
to
receive
(
:matches?
).
and_return
(
true
)
expect
(
get
(
"/foo.gpg"
)).
to
route_to
(
'profiles/gpg_keys#get_keys'
,
username:
'foo'
)
end
end
# emails GET /emails(.:format) emails#index
# emails GET /emails(.:format) emails#index
# POST /keys(.:format) emails#create
# POST /keys(.:format) emails#create
# DELETE /keys/:id(.:format) keys#destroy
# DELETE /keys/:id(.:format) keys#destroy
...
...
spec/support/helpers/gpg_helpers.rb
View file @
cb47d5f0
...
@@ -144,6 +144,145 @@ module GpgHelpers
...
@@ -144,6 +144,145 @@ module GpgHelpers
'5F7EA3981A5845B141ABD522CCFBE19F00AC8B1D'
'5F7EA3981A5845B141ABD522CCFBE19F00AC8B1D'
end
end
def
secret_key2
<<~
KEY
.
strip
-----BEGIN PGP PRIVATE KEY BLOCK-----
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
4f6xMfFu2A==
=3YL6
-----END PGP PRIVATE KEY BLOCK-----
KEY
end
def
public_key2
<<~
KEY
.
strip
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQGNBF+7O0oBDADvRto4K9PT83Lbyp/qaMPIzBbXHB6ljdDoyb+Pn2UrHk9MhB5v
bTgBv+rctOabmimPPalcyaxOQ1GtrYizo1l33YQZupSvaOoStVLWqnBx8eKKcUv8
QucS3S2qFhj9G0tdHW7RW2BGrSwEM09d2xFsFKKAj/4RTTU5idYWrvB24DNcrBh+
iKsoa+rmJf1bwL6Mn9f9NwzundG16qibY/UwMlltQriWaVMn2AKVuu6HrX9pe3g5
Er2Szjc7DZitt6eAy3PmuWHXzDCCvsO7iPxXlywY49hLhDen3/Warwn1pSbp+im4
/0oJExLZBSS1xHbRSQoR6matF0+V/6TQz8Yo3g8z9HgyEtn1V7QJo3PoNrnEl73e
9yslTqVtzba0Q132oRoO7eEYf82KrPOmVGj6Q9LpSXFLfsl3GlPgoBxRZXpT62CV
3rGalIa2yKmcBQtyICjR1+PTIAJcVIPyr92xTo4RfLwVFW0czX7LM2H0FT2Ksj7L
U450ewBz8N6bFDMAEQEAAbQtTmFubmllIEJlcm5oYXJkIDxuYW5uaWUuYmVybmhh
cmRAZXhhbXBsZS5jb20+iQHUBBMBCgA+FiEExEem9r/Zzvj7NxeFVxYlqTAkEXkF
Al+7O0oCGwMFCQPCZwAFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQVxYlqTAk
EXk9xwv/WlJJGJ+QyGeJAhySG3z3bQnFwb2CusF2LbwcAETDgbkfopkkf34Vbb9A
7kM7peZ7Va0Edsg09XdkBUAdaqKQn78HiZJC5n0grXcj1c67AdssYm9TGVM6AC3K
3Vm3wVV0X+ng31rdDpjfIqfYDAvwhMc8H/MHs/dCRSIxEGWK8UKhWLUrX+wN+HNM
VbzWPGwoTMWiDa/ofA9INhqN+u+mJkTaP+a4R3LTgL5hp+kUDOaBNc0rqH7vgj+0
37NTL8vox18J4qgNbRIsywclMYBJDwfA4w1phtsMu1BKPiOu2kue18fyGDtboXUP
FOJjf5OEwJsu+MFogWeAVuHN/eeiqOAFCYW+TT6Ehc6BnJ8vWCMSDgs3t6i94gNZ
tvEty2EAheHEBD1alU4c6S3VENdh5q2KkWIVFxgNtungo03eAVfjUhMjrrEu0LC/
Rizo7Me0kG7rfdn9oIwp4MTn7Cst1wGEWdi9UO4NJf1C+P9rFQuGhMaj+8gb1uBd
jPG8WOOauQGNBF+7O0oBDADhzNAvjiphKHsa4O5s3BePLQ+DJz+KrS8f9mb66to/
w9BlUtnm/L4gVgiIYqGhH7TSDaGhvIDMf3iKKBnKrWeBe0W8cdq3FlzWC/AHUahE
FxFm0l6nq0pOIiAVQ58IPaB/0a5YCY7tU2yfw8llZUN8dWJ7cSsBGpa6Q9/9y4x5
/9VPDPduXRv22KCfDbHXuFS79ubmueFfrOa1CLXRhCy3dUXCyePUYuwxixXJRTJQ
Jm+A6c8TFIL+cji7IEzzDAiNexfGzEfu+Qj1/9PzX8aIn6C5Tf4qB1pcGa4uYr8K
1aCENcVt6+GA5gMdcplYXmtA212RyPqQmnJIjxDdS7AJYcivqG2qF5CvqzKY5/A+
e9+GLyRM36P8LpB8+XHMoYNMNmOl5KX6WZ1tRw/xxgv1iKX3PcqdnoFwsOCNVpTW
lxvjsyve8VQUplORSakIhfKh1VWu7j8AKXWe9S3zMYQDq5G8VrTOVb1pPvPgiNxo
9u1OXi2H9UTXhCWYZ6FIe2UAEQEAAYkBvAQYAQoAJhYhBMRHpva/2c74+zcXhVcW
JakwJBF5BQJfuztKAhsMBQkDwmcAAAoJEFcWJakwJBF5T/ML/3Ml7+493hQuoC9O
3HOANkimc0pGxILVeJmJmnfbMDJ71fU84h2+xAyk2PZc48wVYKju9THJzdRk+XBP
O+G6mSBupSt53JIYb5NijotNTmJmHYpG1yb+9FjDEFWTlxK1mr5wjSUxlGWa/O46
XjxzCSEUP1SknLWbTOucV8KOmPWL3DupvGINIIQxe5eJ9SMjlHvUn4rq8sd11FT2
bQrd+xMx8gP5cearPqB7qVRlHjtOKn29gTV90kIwamRke8KxSoJh+xT057aKI2+M
Cu7RC8TgThmUVCWgwUzXlsw1Qe8ySc6CmjIBftfolQYPDSq1u8RSBAB+t2Xwprvd
edr9SQihzBk5GCGBJ/npEcgF2jk26sJqoXYbvyQGtqSDQ925oP7OstyOE4FTH7sQ
mBvP01Ikdgwkm0cthLSpWY4QI+09Aeg+rZ80EtfvvAKquDGA33no8YGnn+epeLqy
scIh4WG3bIoHk9JlFCcwIp9U65IfR1fTcvlTdzZN4f6xMfFu2A==
=RAwd
-----END PGP PUBLIC KEY BLOCK-----
KEY
end
def
fingerprint2
'C447A6F6BFD9CEF8FB371785571625A930241179'
end
def
names
def
names
[
'Nannie Bernhard'
]
[
'Nannie Bernhard'
]
end
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment