Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F7893030
signature.ex
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
4 KB
Referenced Files
None
Subscribers
None
signature.ex
View Options
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule
Pleroma.Signature
do
@behaviour
HTTPSignatures.Adapter
alias
Pleroma.EctoType.ActivityPub.ObjectValidators
alias
Pleroma.Keys
alias
Pleroma.User
alias
Pleroma.Web.ActivityPub.ActivityPub
import
Plug.Conn
,
only
:
[
put_req_header
:
3
]
@http_signatures_impl
Application
.
compile_env
(
:pleroma
,
[
__MODULE__
,
:http_signatures_impl
],
HTTPSignatures
)
@known_suffixes
[
"/publickey"
,
"/main-key"
]
def
key_id_to_actor_id
(
key_id
)
do
uri
=
key_id
|>
URI
.
parse
()
|>
Map
.
put
(
:fragment
,
nil
)
|>
remove_suffix
(
@known_suffixes
)
maybe_ap_id
=
URI
.
to_string
(
uri
)
case
ObjectValidators.ObjectID
.
cast
(
maybe_ap_id
)
do
{
:ok
,
ap_id
}
->
{
:ok
,
ap_id
}
_
->
case
Pleroma.Web.WebFinger
.
finger
(
maybe_ap_id
)
do
{
:ok
,
%{
"ap_id"
=>
ap_id
}}
->
{
:ok
,
ap_id
}
_
->
{
:error
,
maybe_ap_id
}
end
end
end
defp
remove_suffix
(
uri
,
[
test
|
rest
])
do
if
not
is_nil
(
uri
.
path
)
and
String
.
ends_with?
(
uri
.
path
,
test
)
do
Map
.
put
(
uri
,
:path
,
String
.
replace
(
uri
.
path
,
test
,
""
))
else
remove_suffix
(
uri
,
rest
)
end
end
defp
remove_suffix
(
uri
,
[]),
do
:
uri
def
fetch_public_key
(
conn
)
do
with
{
:ok
,
actor_id
}
<-
get_actor_id
(
conn
),
{
:ok
,
public_key
}
<-
User
.
get_public_key_for_ap_id
(
actor_id
)
do
{
:ok
,
public_key
}
else
e
->
{
:error
,
e
}
end
end
def
refetch_public_key
(
conn
)
do
with
{
:ok
,
actor_id
}
<-
get_actor_id
(
conn
),
{
:ok
,
_user
}
<-
ActivityPub
.
make_user_from_ap_id
(
actor_id
),
{
:ok
,
public_key
}
<-
User
.
get_public_key_for_ap_id
(
actor_id
)
do
{
:ok
,
public_key
}
else
e
->
{
:error
,
e
}
end
end
def
get_actor_id
(
conn
)
do
with
%{
"keyId"
=>
kid
}
<-
HTTPSignatures
.
signature_for_conn
(
conn
),
{
:ok
,
actor_id
}
<-
key_id_to_actor_id
(
kid
)
do
{
:ok
,
actor_id
}
else
e
->
{
:error
,
e
}
end
end
def
sign
(%
User
{
keys
:
keys
}
=
user
,
headers
)
do
with
{
:ok
,
private_key
,
_
}
<-
Keys
.
keys_from_pem
(
keys
)
do
HTTPSignatures
.
sign
(
private_key
,
user
.
ap_id
<>
"
#
main-key"
,
headers
)
end
end
def
signed_date
,
do
:
signed_date
(
NaiveDateTime
.
utc_now
())
def
signed_date
(%
NaiveDateTime
{}
=
date
)
do
Timex
.
format!
(
date
,
"{WDshort}, {0D} {Mshort} {YYYY} {h24}:{m}:{s} GMT"
)
end
@spec
validate_signature
(
Plug.Conn
.
t
(),
String
.
t
())
::
boolean
()
def
validate_signature
(%
Plug.Conn
{}
=
conn
,
request_target
)
do
# Newer drafts for HTTP signatures now use @request-target instead of the
# old (request-target). We'll now support both for incoming signatures.
conn
=
conn
|>
put_req_header
(
"(request-target)"
,
request_target
)
|>
put_req_header
(
"@request-target"
,
request_target
)
@http_signatures_impl
.
validate_conn
(
conn
)
end
@spec
validate_signature
(
Plug.Conn
.
t
())
::
boolean
()
def
validate_signature
(%
Plug.Conn
{}
=
conn
)
do
# This (request-target) is non-standard, but many implementations do it
# this way due to a misinterpretation of
# https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-06
# "path" was interpreted as not having the query, though later examples
# show that it must be the absolute path + query. This behavior is kept to
# make sure most software (Pleroma itself, Mastodon, and probably others)
# do not break.
request_target
=
Enum
.
join
([
String
.
downcase
(
conn
.
method
),
conn
.
request_path
],
" "
)
# This is the proper way to build the @request-target, as expected by
# many HTTP signature libraries, clarified in the following draft:
# https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-11.html#section-2.2.6
# It is the same as before, but containing the query part as well.
proper_target
=
Enum
.
join
([
request_target
,
"?"
,
conn
.
query_string
],
""
)
cond
do
# Normal, non-standard behavior but expected by Pleroma and more.
validate_signature
(
conn
,
request_target
)
->
true
# Has query string and the previous one failed: let's try the standard.
conn
.
query_string
!=
""
->
validate_signature
(
conn
,
proper_target
)
# If there's no query string and signature fails, it's rotten.
true
->
false
end
end
end
File Metadata
Details
Attached
Mime Type
text/x-ruby
Expires
Thu, Oct 2, 4:45 AM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
487318
Default Alt Text
signature.ex (4 KB)
Attached To
Mode
rPUBE pleroma-upstream
Attached
Detach File
Event Timeline
Log In to Comment