Compare commits

...
This repository has been archived on 2024-01-11. You can view files and clone it, but cannot push or open issues or pull requests.

229 commits
main ... old

Author SHA1 Message Date
b54a86285a
Merge branch 'feature-go-ap-inbox-outbox' 2022-06-18 13:29:33 -05:00
fb685bf05a
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-18 13:24:34 -05:00
805ca3d4c0
make fmt 2022-06-18 13:24:32 -05:00
0231dad173
go mod tidy 2022-06-18 13:20:36 -05:00
f67105611c
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-18 13:16:01 -05:00
7c10ab9fde
Change Gitea user agent from the default to Gitea/Version 2022-06-18 13:08:00 -05:00
37d2d01f8f
Use go-ap/jsonld to add @context and marshal JSON 2022-06-18 12:27:11 -05:00
6543
fe18cf7620
Merge branch 'main' into feature-activitypub 2022-06-18 18:36:39 +02:00
6543
7bfadb46ff
Merge branch 'main' into feature-activitypub 2022-06-18 15:19:10 +02:00
47011db720
Add ed25519 to httpsig algorithms 2022-06-17 13:43:26 -05:00
1e563ece83
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-17 11:56:44 -05:00
7446583a0d
go mod tidy 2022-06-17 11:38:56 -05:00
8e6f3fbf46
Update go-ap to fix empty liked collection and removed unneeded HTTP headers 2022-06-17 11:10:51 -05:00
a8dea646a0
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-16 16:40:43 -05:00
dbb1d5ba23
Implement Repository actor endpoints 2022-06-16 16:25:17 -05:00
6543
7e1784fd3f
Merge branch 'main' into feature-activitypub 2022-06-16 22:09:41 +02:00
af2419c5d7
Rate limit federation requests/responses and add better comments 2022-06-16 14:54:16 -05:00
202303e888
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-16 14:19:45 -05:00
7a214dd212
More code cleanup 2022-06-16 14:18:30 -05:00
c67e4189de
make generate-swagger to fix typos
I didn't know that templates/swagger/v1_json.tmpl was machine-generated... 😭
2022-06-16 12:34:03 -05:00
37b913476e
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-16 12:30:33 -05:00
b35490c53d
Merge remote-tracking branch 'upstream/main' into feature-activitypub 2022-06-16 11:42:37 -05:00
c118dacde7
Move getting the RFC 2616 time to a separate function 2022-06-16 11:17:05 -05:00
2a013b8fe4
make generate-swagger
For some reason I didn't realize that /templates/swagger/v1_json.tmpl was machine-generated by make generate-swagger... I've been editing it by hand for three months! 🤦
2022-06-16 11:11:57 -05:00
3a8b8408b4
Fix failing ActivityPubMissingPerson test
We now use ctx.ContextUser so the message printed out when a user does not exist is slightly different
2022-06-16 11:08:24 -05:00
6602fd136e
Add more better comments 2022-06-16 11:03:53 -05:00
0c49fea641
Don't multiply Federation.MaxSize by 1<<20 twice 2022-06-16 11:00:24 -05:00
6336ba2e83
Add better comments 2022-06-16 10:59:36 -05:00
db13e1d6a1
Add a warning about changing settings that can break federation 2022-06-16 10:53:18 -05:00
ad62049f0b
Fix failing ActivityPubPerson integration test by checking the correct field for username 2022-06-15 20:59:57 -05:00
fb1f551153
Move setting key constants to models/user/setting_keys.go 2022-06-15 20:56:50 -05:00
a2d5202d4e
Limit maximum ActivityPub request and response sizes to a configurable setting 2022-06-15 20:43:19 -05:00
e9e8a03e08
Use activitypub.ActivityStreamsContentType for Person response Content Type 2022-06-15 20:29:01 -05:00
3fe44596de
Revert "Use ctx.JSON in Person response to make code cleaner"
This doesn't work because the ctx.JSON() function already sends the response out and it's too late to edit the headers.

This reverts commit 95aad98897.
2022-06-15 20:26:47 -05:00
95aad98897
Use ctx.JSON in Person response to make code cleaner 2022-06-15 20:22:05 -05:00
d76159a2da
Implement ForgeFed Respository type over go-ap 2022-06-15 17:55:02 -05:00
06372f9fd0
Fix mirrors log spam 2022-06-15 12:35:52 -05:00
c474f683af
Merge branch 'feature-go-ap-inbox-outbox' 2022-06-15 11:57:12 -05:00
f46a4d3c19
Make visiting remote users' profiles in the web UI redirect to their instance 2022-06-15 11:38:33 -05:00
55d9f66cd6
Add back remote interactions item in WebFinger response 2022-06-15 11:00:17 -05:00
32ccd908c0
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-15 10:59:12 -05:00
e5ed91d986
Merge remote-tracking branch 'github/feature-activitypub' into feature-activitypub 2022-06-15 10:56:14 -05:00
6543
46b344ca3e
Merge branch 'main' into feature-activitypub 2022-06-15 16:27:31 +02:00
6543
58401634d8
Update routers/web/webfinger.go 2022-06-15 08:50:26 +02:00
6543
172c39f781 use const for key values 2022-06-15 08:47:32 +02:00
db51a8e506
Merge branch 'feature-go-ap-inbox-outbox' 2022-06-14 21:36:05 -05:00
b62b8bdbf1
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-14 21:35:40 -05:00
f48115f5f0
Go back to using ap.IRI to generate inbox and outbox IRIs 2022-06-14 21:34:37 -05:00
1da4849ad7
Merge remote-tracking branch 'github/feature-activitypub' into feature-activitypub 2022-06-14 21:33:31 -05:00
2fe9bacac0
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-14 21:13:07 -05:00
14cfd8de23
Revert "If httpsig verification fails, fix Host header and try again"
This reverts commit f53e46c721.

The bug was actually caused by nginx messing up the Host header when reverse-proxying since I didn't have the line `proxy_set_header Host $host;` in my nginx config for Gitea.
2022-06-14 21:11:55 -05:00
6543
c05bad8d41
Merge branch 'main' into feature-activitypub 2022-06-15 03:24:48 +02:00
6543
f8ad1a832f
Apply suggestions from code review
Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
2022-06-15 03:19:34 +02:00
bcc81c3093
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-14 16:31:28 -05:00
f53e46c721
If httpsig verification fails, fix Host header and try again
This fixes a very rare bug when Gitea and another AP server (confirmed to happen with Mastodon) are running on the same machine, Gitea fails to verify incoming HTTP signatures. This is because the other AP server creates the sig with the public Gitea domain as the Host. However, when Gitea receives the request, the Host header is instead localhost, so the signature verification fails. Manually changing the host header to the correct value and trying the verification again fixes the bug.
2022-06-14 16:23:08 -05:00
fcba187a00
Improve debug logging 2022-06-14 16:09:21 -05:00
f59cd33db9
Merge branch 'feature-go-ap-inbox-outbox' 2022-06-14 13:03:00 -05:00
abd0d1f16f
Add @context when sending activities 2022-06-14 12:58:00 -05:00
a07cd5ecc0
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-14 12:40:13 -05:00
a3120079a5
Make sure Person IRIs are generated correctly
This commit ensures that if the setting.AppURL is something like "http://127.0.0.1:42567" (like in the integration tests), a trailing slash will be added after that URL.
2022-06-14 12:30:36 -05:00
d06772b376
Return if marshalling error 2022-06-14 12:26:06 -05:00
faf2855244
Add new federation settings to app.example.ini and config-cheat-sheet 2022-06-14 12:23:20 -05:00
a4403e4e80
Move httpsig algs constant slice to modules/setting/federation.go 2022-06-14 12:16:32 -05:00
e60158c70b
Make sure API responses always refer to username in original case
Copied from what I wrote on #19133 discussion: Handling username case is a very tricky issue and I've already encountered a Mastodon <-> Gitea federation bug due to Gitea considering Ta180m and ta180m to be the same user while Mastodon thinks they are two different users. I think the best way forward is for Gitea to only use the original case version of the username for federation so other AP software don't get confused.
2022-06-14 12:01:41 -05:00
add8469813
Merge branch 'feature-activitypub' of github.com:Ta180m/Gitea into feature-activitypub 2022-06-14 10:54:19 -05:00
6543
3f2d8b015f
dont drop err 2022-06-14 14:26:41 +02:00
6543
900ceb2dfd
make fmt 2022-06-14 14:12:00 +02:00
6543
2706e89138
Merge branch 'main' into feature-activitypub 2022-06-14 14:10:40 +02:00
08eebffb0e
Make sure HTTP request Date in GMT 2022-06-13 23:10:36 -05:00
3522fb1c36
Merge branch 'feature-go-ap-inbox-outbox' 2022-06-13 20:52:29 -05:00
ea3d61faa1
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-13 20:52:09 -05:00
d749f8ff4f
Rename pkey to pubKey 2022-06-13 20:51:49 -05:00
9fe057a93e
make fmt 2022-06-13 19:31:11 -05:00
da1be7167e
Correctly create remote user 2022-06-13 19:30:08 -05:00
22960444db
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-13 19:09:36 -05:00
3e9a69c8d3
Use UTC instead of GMT 2022-06-13 19:09:09 -05:00
4bcb6a16b2
Move duplicate response code to response.go 2022-06-13 18:21:45 -05:00
6010b9ca94
Merge branch 'feature-go-ap-inbox-outbox' 2022-06-13 17:57:04 -05:00
9a56cc5a63
Send Follow Accept 2022-06-13 17:55:50 -05:00
d9e2eb0ef5
Make sure Person endpoint returns Content-Type application/activity+json 2022-06-13 17:55:49 -05:00
af96558f9c
Add followers and following API endpoints and create federated user in DB if not exists 2022-06-13 17:54:51 -05:00
aa8ba2277f
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-13 17:20:07 -05:00
f88979326c
Make sure Person endpoint has Content-Type application/activity+json and includes PreferredUsername, URL, and Icon
Setting the correct Content-Type is essential for federating with Mastodon
2022-06-13 17:14:41 -05:00
ed2a6f5348
make lint-backend 2022-06-13 16:53:17 -05:00
d2b4667d89
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-13 16:50:32 -05:00
718f35aab6
Merge remote-tracking branch 'upstream/main' into feature-activitypub 2022-06-13 16:49:36 -05:00
c347aecef1
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox 2022-06-13 16:21:13 -05:00
4b41ba20d6
Send Follow Accept 2022-06-13 16:16:52 -05:00
eb7a0bb5ef
Make sure Person endpoint returns Content-Type application/activity+json 2022-06-13 16:16:40 -05:00
b6b7fe27b6
WebFinger: Add CORS header and fix Href -> Template for remote interactions
The CORS header is needed due to https://datatracker.ietf.org/doc/html/rfc7033#section-5 and fixes some Peertube <-> Gitea federation issues
2022-06-13 15:40:26 -05:00
798381ee88
WebFinger: Add CORS header and fix Href -> Template for remote interactions
The CORS header is needed due to https://datatracker.ietf.org/doc/html/rfc7033#section-5 and fixes some Peertube <-> Gitea federation issues
2022-06-13 15:39:20 -05:00
bc96a01c14
Merge branch 'feature-activitypub' 2022-06-13 11:49:04 -05:00
a5b00ec4a5
Force CI rerun 2022-06-13 09:16:42 -05:00
d7b81f551d
make fmt 2022-06-13 09:03:10 -05:00
10396a57ea
Add followers and following API endpoints and create federated user in DB if not exists 2022-06-12 21:51:14 -05:00
d91c61f8fa
Update TestWebFinger to check for ActivityPub IRI in aliases 2022-06-12 21:11:14 -05:00
baf008e1d6
Update TestWebFinger to check for ActivityPub IRI in aliases 2022-06-12 21:10:44 -05:00
89643dd441
Merge branch 'feature-activitypub' 2022-06-12 17:02:22 -05:00
5823d8150a
Add actor IRI and remote interaction URL to WebFinger response 2022-06-12 17:01:30 -05:00
4d0bb6308a
Merge remote-tracking branch 'upstream/main' 2022-06-12 16:51:55 -05:00
da59a0ac19
Copy code from feature-go-ap-inbox-outbox branch 2022-06-12 16:50:02 -05:00
805edf4555
Delete old go-fed inbox/outbox implementation code 2022-06-12 16:43:41 -05:00
78c8fe0b5a
Implement POSTing to inbox and GETting outbox by reusing the Action table 2022-06-12 16:43:08 -05:00
408e69eb39
Implement POSTing to inbox and GETting outbox by reusing the Action table 2022-06-12 16:15:54 -05:00
191919e7fa
Merge remote-tracking branch 'upstream/main' into feature-activitypub 2022-06-12 14:25:41 -05:00
d1f14ff2c7
Move httpsig algos slice to an init() function 2022-06-12 14:24:47 -05:00
76f06cee31
Remove another LogSQL from ActivityPub person test 2022-06-11 21:18:15 -05:00
6074222377
Code cleanup 2022-06-11 21:15:45 -05:00
1a8955dc4f
Stop HomeDir is empty error messages when pushing 2022-06-11 18:44:37 -05:00
80e137461a
Merge remote-tracking branch 'upstream/main' 2022-06-11 18:43:31 -05:00
7658649d61
Merge remote-tracking branch 'upstream/main' into feature-activitypub 2022-06-11 18:36:41 -05:00
75dd8c366a
Merge branch 'feature-activitypub' 2022-06-11 12:44:53 -05:00
528c282d68
Correctly add inbox/outbox IRIs to person 2022-06-11 12:40:10 -05:00
cf6aed386d
Use @mariusor's suggestions for idiomatic go-ap usage 2022-06-11 11:00:45 -05:00
6543
f7da251c5d
Merge branch 'main' into feature-activitypub 2022-06-11 16:59:18 +02:00
051d1002b4
Merge branch 'feature-activitypub' 2022-06-10 14:45:00 -05:00
66b1761738
Fix lint error 2022-06-10 13:28:50 -05:00
7428ff0736
Fix TestActivityPubPersonInbox segfault 2022-06-10 12:30:13 -05:00
fc58ab6b25
Force CI rerun 2022-06-10 11:29:39 -05:00
d487a76572
Correctly decode JSON in api_activitypub_person_test.go 2022-06-10 11:19:23 -05:00
86a3221563
Fix CI errors by adding @context to Person() and making sure types match 2022-06-10 11:04:07 -05:00
46cab80ef4
Fix JSON unmarshall error 2022-06-10 10:37:55 -05:00
6543
2f0a0b1216
Merge branch 'main' into feature-activitypub 2022-06-10 05:36:02 +02:00
94fbd80b7b
Clean up go.sum 2022-06-09 18:56:43 -05:00
a8cb4a80bf
Convert remaining code to go-ap 2022-06-09 17:59:43 -05:00
57e6b67095
make fmt 2022-06-09 17:43:54 -05:00
67e0fcdd76
Run go mod tidy to fix missing modules in go.mod and go.sum 2022-06-09 17:22:59 -05:00
1e57f01001
Merge remote-tracking branch 'github/main' into feature-activitypub 2022-06-09 17:18:33 -05:00
6ac8e53177
Merge remote-tracking branch 'github/main' 2022-06-09 17:01:31 -05:00
f3d7f7fc5b
Merge remote-tracking branch 'github/main' 2022-05-26 16:25:55 -05:00
e5d7a28269
Comment out broken go-fed code 2022-05-26 16:25:39 -05:00
98dad2053c
Use go-ap instead of go-fed 2022-05-24 14:40:47 -05:00
becdf5e1f1
Use go-ap instead of go-fed 2022-05-23 11:43:59 -05:00
ebea73a1fa
Fix compile errors 2022-05-21 13:15:59 -05:00
00bee2dab8
Merge remote-tracking branch 'github/main' 2022-05-21 10:35:00 -05:00
501a39fb98
Merge remote-tracking branch 'github/feature-activitypub' into feature-activitypub 2022-05-09 19:13:16 -05:00
364838c11b
Fix lint errors 2022-05-09 19:11:08 -05:00
6f567d0c01
Fix lint errors 2022-05-09 19:10:45 -05:00
6543
609fcc7514
Merge branch 'master' into feature-activitypub 2022-05-09 21:01:27 +02:00
6543
55c5e930db
fmt 2022-05-09 19:48:10 +02:00
6543
07150b33ba
Merge branch 'master' into feature-activitypub 2022-05-09 19:47:40 +02:00
1b65add4f7
Merge remote-tracking branch 'gitea/main' 2022-04-30 21:47:56 -05:00
696542903e
Move notes.md to wiki 2022-04-28 08:13:09 -05:00
5dca807463
Clean up notes.md formatting 2022-04-26 19:38:54 -05:00
69c788566e
Add notes about Gitea federation development and the new repo 2022-04-26 19:37:21 -05:00
1e2f9863e7
Merge branch 'go-gitea:main' into dev 2022-04-26 19:30:09 -05:00
aa962c6ee9
Add actor IRI and remote interaction URL to WebFinger response 2022-04-26 18:52:18 -05:00
KN4CK3R
5d61e5955b
Add user profile as alias. 2022-04-26 18:52:18 -05:00
KN4CK3R
0d120f8a8d
Add visible check. 2022-04-26 18:52:18 -05:00
KN4CK3R
523ca3d89b
Implemented Webfinger endpoint. 2022-04-26 18:52:18 -05:00
702a963308
Move /#main-key to #main-key in tests 2022-04-26 18:52:18 -05:00
6a03890684
Customize homepage description for my exogit instance 2022-04-26 08:47:02 -05:00
e8987048c1
Add notes from the Gitea federation meeting 2022-04-25 16:00:39 -05:00
b80000ab98
Merge pull request #1 from Ta180m/imgbot
[ImgBot] Optimize images
2022-04-25 10:58:20 -05:00
KN4CK3R
8c14f5336f
Added tests. 2022-04-25 10:55:50 -05:00
KN4CK3R
ec54f698d9
Use url.Parse instead of regexp. 2022-04-25 10:55:49 -05:00
KN4CK3R
d03097712a
Fail if KeepEmailPrivate. 2022-04-25 10:55:49 -05:00
2821ce4a0c
Update federated following TODO list 2022-04-24 14:32:28 -05:00
a904349864
Add following and follower ActivityStreams endpoints 2022-04-24 14:23:11 -05:00
27cd913f40
Cross out finished WebFinger stuff from notes 2022-04-24 13:55:54 -05:00
9b763c2f0e
Notes about federated starring 2022-04-24 13:41:16 -05:00
1b9a9df5ec
Update TODO list in notes.md now that WebFinger is done 2022-04-22 12:14:12 -05:00
543fbe0655
Add actor IRI and remote interaction URL to WebFinger response 2022-04-22 11:10:26 -05:00
KN4CK3R
70aa564632
Add user profile as alias. 2022-04-22 09:09:44 -05:00
KN4CK3R
8f5a3fa43e
Add visible check. 2022-04-22 09:09:43 -05:00
90cda5f2a1
Reformating using make fmt 2022-04-21 22:28:31 -05:00
17a2d51952
Use AddToOutbox for sending follow requests 2022-04-21 22:00:01 -05:00
2b44be9a17
Add a TODO list to notes 2022-04-21 20:53:41 -05:00
40f6ed2dd8
Add more notes about federated following 2022-04-21 20:53:41 -05:00
eed4644409
Add notes about remote users 2022-04-21 20:53:41 -05:00
3f77a36a2c
Add inbox/outbox notes 2022-04-21 20:53:40 -05:00
c1b8463251
Get federated following to work 2022-04-21 20:53:40 -05:00
608e4036e5
Actually follow local user when processing follow request 2022-04-21 20:53:40 -05:00
f9b38495fd
Rig up inbox/outbox to the API 2022-04-21 20:53:40 -05:00
d2c5df88eb
Implement inbox 2022-04-21 20:53:39 -05:00
2b243acf71
Implement outbox 2022-04-21 20:53:39 -05:00
KN4CK3R
95fdec2739
Implemented Webfinger endpoint. 2022-04-21 20:38:30 -05:00
9dfe4bc8a6
Move /#main-key to #main-key in tests 2022-04-21 20:36:27 -05:00
15427d5131
Make pubKey IRI #main-key instead of /#main-key 2022-04-21 20:36:27 -05:00
4937aab43d
Use named constant for httpsigExpirationTime 2022-04-21 20:36:27 -05:00
016d2d410b
Use system timezone instead of setting.DefaultUILocation 2022-04-21 20:36:27 -05:00
6e802b549d
Remove unneeded copy 2022-04-21 20:36:27 -05:00
273ffae0e4
Clean up some variable declarations 2022-04-21 20:36:26 -05:00
89a539815a
Check if digest algo is supported in setting module 2022-04-21 20:36:26 -05:00
d8c401dead
Use time.RFC1123 and make the http.Client proxy-aware 2022-04-21 20:36:26 -05:00
231ead4d48
Clean up whitespace with make fmt 2022-04-21 20:36:26 -05:00
f1ec41b339
Use the httplib module instead of http for GET requests 2022-04-21 20:36:26 -05:00
7d819f5e89
Rename hack_16834 to user_settings
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-04-21 20:36:25 -05:00
98664a7c84
Cleanup, handle invalid usernames for ActivityPub person GET request
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-04-21 20:36:25 -05:00
9c41737419
Assert if json.Unmarshal succeeds
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-04-21 20:36:25 -05:00
944d0afa9f
Remove LogSQL from ActivityPub person test
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-04-21 20:36:25 -05:00
6e13733898
Run make fmt again, fix err var redeclaration
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-04-21 20:36:25 -05:00
2d9f8e1f9b
Use Gitea JSON library, add assert for pkp
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-04-21 20:36:24 -05:00
764bbdbb70
Run make fmt and make generate-swagger
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-04-21 20:36:24 -05:00
d223aa69e3
Change 2021 to 2022, properly format package imports
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-04-21 20:36:24 -05:00
8e6b33b3e1
Fix CI checks-backend errors with go mod tidy
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-04-21 20:36:24 -05:00
Loïc Dachary
c946b9e3a4
activitypub: hack_16834
Signed-off-by: Loïc Dachary <loic@dachary.org>
2022-04-21 20:36:24 -05:00
Loïc Dachary
550901e6fb
activitypub: implement the ReqSignature middleware
Signed-off-by: Loïc Dachary <loic@dachary.org>
2022-04-21 20:36:23 -05:00
Loïc Dachary
f5a70ebe32
activitypub: signing http client
Signed-off-by: Loïc Dachary <loic@dachary.org>
2022-04-21 20:36:23 -05:00
Loïc Dachary
fcbbf6dbe7
activitypub: go-fed conformant Clock instance
Signed-off-by: Loïc Dachary <loic@dachary.org>
2022-04-21 20:36:23 -05:00
Loïc Dachary
eb3aaa2050
activitypub: add the public key to Person (#14186)
Refs: https://github.com/go-gitea/gitea/issues/14186

Signed-off-by: Loïc Dachary <loic@dachary.org>
2022-04-21 20:36:23 -05:00
Loïc Dachary
49db112ccf
activitypub: implement /api/v1/activitypub/user/{username} (#14186)
Return informations regarding a Person (as defined in ActivityStreams
https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person).

Refs: https://github.com/go-gitea/gitea/issues/14186

Signed-off-by: Loïc Dachary <loic@dachary.org>
2022-04-21 20:36:23 -05:00
Loïc Dachary
66483a244b
go.mod: add go-fed/{httpsig,activity/pub,activity/streams} dependency
go get github.com/go-fed/activity/streams@master
go get github.com/go-fed/activity/pub@master
go get github.com/go-fed/httpsig@master
2022-04-21 20:36:22 -05:00
7931e210e5
Make pubKey IRI #main-key instead of /#main-key 2022-04-13 11:19:17 -05:00
5139b3dc19
Use named constant for httpsigExpirationTime 2022-04-13 09:05:24 -05:00
7ea5e108a5
Use system timezone instead of setting.DefaultUILocation 2022-03-30 17:51:44 -05:00
fdae736f22
Remove unneeded copy 2022-03-30 16:29:47 -05:00
1da0d49de7
Clean up some variable declarations 2022-03-30 15:52:52 -05:00
65016b2664
Check if digest algo is supported in setting module 2022-03-29 16:38:27 -05:00
d1a53f7d6a
Use time.RFC1123 and make the http.Client proxy-aware 2022-03-28 12:37:52 -05:00
373a84a8e2
Clean up whitespace with make fmt 2022-03-27 12:25:56 -05:00
21c56f8e94
Use the httplib module instead of http for GET requests 2022-03-27 12:25:27 -05:00
3ed4a71a4c
Rename hack_16834 to user_settings
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-03-25 11:53:16 -05:00
46973f99fa
Cleanup, handle invalid usernames for ActivityPub person GET request
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-03-24 18:44:44 -05:00
ebef769703
Assert if json.Unmarshal succeeds
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-03-20 10:53:05 -05:00
d75809aeee
Remove LogSQL from ActivityPub person test
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-03-20 10:53:05 -05:00
456ed42d3e
Run make fmt again, fix err var redeclaration
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-03-20 10:52:49 -05:00
ea4129e888
Use Gitea JSON library, add assert for pkp
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-03-19 16:36:44 -05:00
f9e33d97cc
Run make fmt and make generate-swagger
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-03-19 09:14:08 -05:00
b480c52f60
Change 2021 to 2022, properly format package imports
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-03-19 08:55:58 -05:00
2a8864fe43
Fix CI checks-backend errors with go mod tidy
Signed-off-by: Anthony Wang <ta180m@pm.me>
2022-03-19 08:54:32 -05:00
Loïc Dachary
b342241abc
activitypub: hack_16834
Signed-off-by: Loïc Dachary <loic@dachary.org>
2022-03-18 17:34:10 -05:00
Loïc Dachary
97fedf2616
activitypub: implement the ReqSignature middleware
Signed-off-by: Loïc Dachary <loic@dachary.org>
2022-03-18 17:34:09 -05:00
Loïc Dachary
15c1f6218c
activitypub: signing http client
Signed-off-by: Loïc Dachary <loic@dachary.org>
2022-03-18 17:34:09 -05:00
Loïc Dachary
e8907c3c9e
activitypub: go-fed conformant Clock instance
Signed-off-by: Loïc Dachary <loic@dachary.org>
2022-03-18 17:34:09 -05:00
Loïc Dachary
678a56fbf8
activitypub: add the public key to Person (#14186)
Refs: https://github.com/go-gitea/gitea/issues/14186

Signed-off-by: Loïc Dachary <loic@dachary.org>
2022-03-18 17:34:09 -05:00
Loïc Dachary
4951af4d99
activitypub: implement /api/v1/activitypub/user/{username} (#14186)
Return informations regarding a Person (as defined in ActivityStreams
https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person).

Refs: https://github.com/go-gitea/gitea/issues/14186

Signed-off-by: Loïc Dachary <loic@dachary.org>
2022-03-18 17:33:29 -05:00
Loïc Dachary
f2db473b0d
go.mod: add go-fed/{httpsig,activity/pub,activity/streams} dependency
go get github.com/go-fed/activity/streams@master
go get github.com/go-fed/activity/pub@master
go get github.com/go-fed/httpsig@master
2022-03-18 17:33:20 -05:00
ImgBotApp
539e874579
[ImgBot] Optimize images
*Total -- 154.49kb -> 127.69kb (17.34%)

/public/vendor/plugins/pdfjs/web/images/annotation-noicon.svg -- 0.15kb -> 0.08kb (46.84%)
/modules/avatar/testdata/avatar.jpeg -- 0.51kb -> 0.28kb (44.91%)
/public/img/emoji/git.png -- 4.89kb -> 2.95kb (39.58%)
/public/img/emoji/gitlab.png -- 6.71kb -> 4.62kb (31.24%)
/public/vendor/plugins/pdfjs/web/images/annotation-note.svg -- 1.02kb -> 0.70kb (31.12%)
/public/img/emoji/gogs.png -- 11.52kb -> 8.34kb (27.56%)
/public/img/wechatwork.png -- 9.12kb -> 6.65kb (27.14%)
/public/img/failed.png -- 10.75kb -> 8.18kb (23.89%)
/public/vendor/plugins/pdfjs/web/images/annotation-check.svg -- 0.41kb -> 0.31kb (22.65%)
/public/vendor/plugins/pdfjs/web/images/annotation-newparagraph.svg -- 0.42kb -> 0.32kb (22.54%)
/web_src/svg/gitea-gogs.svg -- 6.23kb -> 4.84kb (22.39%)
/public/img/emoji/codeberg.png -- 8.12kb -> 6.32kb (22.14%)
/public/vendor/plugins/pdfjs/web/images/annotation-insert.svg -- 0.40kb -> 0.31kb (22.06%)
/public/img/auth/mastodon.png -- 4.99kb -> 3.95kb (20.79%)
/docs/static/authorize.png -- 18.51kb -> 14.79kb (20.1%)
/public/vendor/plugins/pdfjs/web/images/annotation-comment.svg -- 0.86kb -> 0.73kb (15.63%)
/docs/static/cloudron.svg -- 15.26kb -> 12.96kb (15.09%)
/public/img/matrix.svg -- 1.22kb -> 1.06kb (13.09%)
/public/vendor/plugins/pdfjs/web/images/annotation-paragraph.svg -- 1.12kb -> 0.97kb (12.69%)
/public/img/emoji/github.png -- 13.78kb -> 12.44kb (9.76%)
/public/img/auth/azuread.png -- 3.03kb -> 2.75kb (9.26%)
/public/img/auth/azureadv2.png -- 3.03kb -> 2.75kb (9.26%)
/public/vendor/plugins/pdfjs/web/images/annotation-help.svg -- 2.12kb -> 1.96kb (7.29%)
/public/vendor/plugins/pdfjs/web/images/annotation-key.svg -- 1.42kb -> 1.33kb (6.47%)
/assets/logo.svg -- 2.55kb -> 2.41kb (5.4%)
/public/img/emoji/gitea.png -- 12.62kb -> 12.02kb (4.72%)
/web_src/svg/fontawesome-windows.svg -- 0.28kb -> 0.27kb (3.5%)
/public/vendor/plugins/pdfjs/web/images/secondaryToolbarButton-selectTool@2x.png -- 1.04kb -> 1.01kb (3.47%)
/web_src/svg/fontawesome-openid.svg -- 0.38kb -> 0.37kb (2.54%)
/web_src/svg/gitea-gitlab.svg -- 0.40kb -> 0.40kb (0.98%)
/web_src/svg/gitea-git.svg -- 0.67kb -> 0.67kb (0.58%)
/public/vendor/plugins/pdfjs/web/images/loading-icon.gif -- 2.49kb -> 2.48kb (0.35%)
/web_src/svg/gitea-github.svg -- 2.42kb -> 2.42kb (0.16%)
/public/img/auth/microsoftonline.png -- 0.77kb -> 0.77kb (0.13%)
/public/img/auth/openid_connect.svg -- 5.30kb -> 5.29kb (0.02%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
2022-03-10 14:13:12 +00:00
66 changed files with 1746 additions and 333 deletions

View file

@ -1,31 +1 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="main_outline" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 640 640" style="enable-background:new 0 0 640 640;" xml:space="preserve">
<g>
<path id="teabag" style="fill:#FFFFFF" d="M395.9,484.2l-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5,21.2-17.9,33.8-11.8
c17.2,8.3,27.1,13,27.1,13l-0.1-109.2l16.7-0.1l0.1,117.1c0,0,57.4,24.2,83.1,40.1c3.7,2.3,10.2,6.8,12.9,14.4
c2.1,6.1,2,13.1-1,19.3l-61,126.9C423.6,484.9,408.4,490.3,395.9,484.2z"/>
<g>
<g>
<path style="fill:#609926" d="M622.7,149.8c-4.1-4.1-9.6-4-9.6-4s-117.2,6.6-177.9,8c-13.3,0.3-26.5,0.6-39.6,0.7c0,39.1,0,78.2,0,117.2
c-5.5-2.6-11.1-5.3-16.6-7.9c0-36.4-0.1-109.2-0.1-109.2c-29,0.4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5
c-9.8-0.6-22.5-2.1-39,1.5c-8.7,1.8-33.5,7.4-53.8,26.9C-4.9,212.4,6.6,276.2,8,285.8c1.7,11.7,6.9,44.2,31.7,72.5
c45.8,56.1,144.4,54.8,144.4,54.8s12.1,28.9,30.6,55.5c25,33.1,50.7,58.9,75.7,62c63,0,188.9-0.1,188.9-0.1s12,0.1,28.3-10.3
c14-8.5,26.5-23.4,26.5-23.4s12.9-13.8,30.9-45.3c5.5-9.7,10.1-19.1,14.1-28c0,0,55.2-117.1,55.2-231.1
C633.2,157.9,624.7,151.8,622.7,149.8z M125.6,353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6,321.8,60,295.4
c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5,38.5-30c13.8-3.7,31-3.1,31-3.1s7.1,59.4,15.7,94.2c7.2,29.2,24.8,77.7,24.8,77.7
S142.5,359.9,125.6,353.9z M425.9,461.5c0,0-6.1,14.5-19.6,15.4c-5.8,0.4-10.3-1.2-10.3-1.2s-0.3-0.1-5.3-2.1l-112.9-55
c0,0-10.9-5.7-12.8-15.6c-2.2-8.1,2.7-18.1,2.7-18.1L322,273c0,0,4.8-9.7,12.2-13c0.6-0.3,2.3-1,4.5-1.5c8.1-2.1,18,2.8,18,2.8
l110.7,53.7c0,0,12.6,5.7,15.3,16.2c1.9,7.4-0.5,14-1.8,17.2C474.6,363.8,425.9,461.5,425.9,461.5z"/>
<path style="fill:#609926" d="M326.8,380.1c-8.2,0.1-15.4,5.8-17.3,13.8c-1.9,8,2,16.3,9.1,20c7.7,4,17.5,1.8,22.7-5.4
c5.1-7.1,4.3-16.9-1.8-23.1l24-49.1c1.5,0.1,3.7,0.2,6.2-0.5c4.1-0.9,7.1-3.6,7.1-3.6c4.2,1.8,8.6,3.8,13.2,6.1
c4.8,2.4,9.3,4.9,13.4,7.3c0.9,0.5,1.8,1.1,2.8,1.9c1.6,1.3,3.4,3.1,4.7,5.5c1.9,5.5-1.9,14.9-1.9,14.9
c-2.3,7.6-18.4,40.6-18.4,40.6c-8.1-0.2-15.3,5-17.7,12.5c-2.6,8.1,1.1,17.3,8.9,21.3c7.8,4,17.4,1.7,22.5-5.3
c5-6.8,4.6-16.3-1.1-22.6c1.9-3.7,3.7-7.4,5.6-11.3c5-10.4,13.5-30.4,13.5-30.4c0.9-1.7,5.7-10.3,2.7-21.3
c-2.5-11.4-12.6-16.7-12.6-16.7c-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3c4.7-9.7,9.4-19.3,14.1-29
c-4.1-2-8.1-4-12.2-6.1c-4.8,9.8-9.7,19.7-14.5,29.5c-6.7-0.1-12.9,3.5-16.1,9.4c-3.4,6.3-2.7,14.1,1.9,19.8
C343.2,346.5,335,363.3,326.8,380.1z"/>
</g>
</g>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="main_outline" x="0" y="0" version="1.1" viewBox="0 0 640 640" xml:space="preserve" style="enable-background:new 0 0 640 640"><g><path id="teabag" d="M395.9,484.2l-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5,21.2-17.9,33.8-11.8 c17.2,8.3,27.1,13,27.1,13l-0.1-109.2l16.7-0.1l0.1,117.1c0,0,57.4,24.2,83.1,40.1c3.7,2.3,10.2,6.8,12.9,14.4 c2.1,6.1,2,13.1-1,19.3l-61,126.9C423.6,484.9,408.4,490.3,395.9,484.2z" style="fill:#fff"/><g><g><path style="fill:#609926" d="M622.7,149.8c-4.1-4.1-9.6-4-9.6-4s-117.2,6.6-177.9,8c-13.3,0.3-26.5,0.6-39.6,0.7c0,39.1,0,78.2,0,117.2 c-5.5-2.6-11.1-5.3-16.6-7.9c0-36.4-0.1-109.2-0.1-109.2c-29,0.4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5 c-9.8-0.6-22.5-2.1-39,1.5c-8.7,1.8-33.5,7.4-53.8,26.9C-4.9,212.4,6.6,276.2,8,285.8c1.7,11.7,6.9,44.2,31.7,72.5 c45.8,56.1,144.4,54.8,144.4,54.8s12.1,28.9,30.6,55.5c25,33.1,50.7,58.9,75.7,62c63,0,188.9-0.1,188.9-0.1s12,0.1,28.3-10.3 c14-8.5,26.5-23.4,26.5-23.4s12.9-13.8,30.9-45.3c5.5-9.7,10.1-19.1,14.1-28c0,0,55.2-117.1,55.2-231.1 C633.2,157.9,624.7,151.8,622.7,149.8z M125.6,353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6,321.8,60,295.4 c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5,38.5-30c13.8-3.7,31-3.1,31-3.1s7.1,59.4,15.7,94.2c7.2,29.2,24.8,77.7,24.8,77.7 S142.5,359.9,125.6,353.9z M425.9,461.5c0,0-6.1,14.5-19.6,15.4c-5.8,0.4-10.3-1.2-10.3-1.2s-0.3-0.1-5.3-2.1l-112.9-55 c0,0-10.9-5.7-12.8-15.6c-2.2-8.1,2.7-18.1,2.7-18.1L322,273c0,0,4.8-9.7,12.2-13c0.6-0.3,2.3-1,4.5-1.5c8.1-2.1,18,2.8,18,2.8 l110.7,53.7c0,0,12.6,5.7,15.3,16.2c1.9,7.4-0.5,14-1.8,17.2C474.6,363.8,425.9,461.5,425.9,461.5z"/><path style="fill:#609926" d="M326.8,380.1c-8.2,0.1-15.4,5.8-17.3,13.8c-1.9,8,2,16.3,9.1,20c7.7,4,17.5,1.8,22.7-5.4 c5.1-7.1,4.3-16.9-1.8-23.1l24-49.1c1.5,0.1,3.7,0.2,6.2-0.5c4.1-0.9,7.1-3.6,7.1-3.6c4.2,1.8,8.6,3.8,13.2,6.1 c4.8,2.4,9.3,4.9,13.4,7.3c0.9,0.5,1.8,1.1,2.8,1.9c1.6,1.3,3.4,3.1,4.7,5.5c1.9,5.5-1.9,14.9-1.9,14.9 c-2.3,7.6-18.4,40.6-18.4,40.6c-8.1-0.2-15.3,5-17.7,12.5c-2.6,8.1,1.1,17.3,8.9,21.3c7.8,4,17.4,1.7,22.5-5.3 c5-6.8,4.6-16.3-1.1-22.6c1.9-3.7,3.7-7.4,5.6-11.3c5-10.4,13.5-30.4,13.5-30.4c0.9-1.7,5.7-10.3,2.7-21.3 c-2.5-11.4-12.6-16.7-12.6-16.7c-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3c4.7-9.7,9.4-19.3,14.1-29 c-4.1-2-8.1-4-12.2-6.1c-4.8,9.8-9.7,19.7-14.5,29.5c-6.7-0.1-12.9,3.5-16.1,9.4c-3.4,6.3-2.7,14.1,1.9,19.8 C343.2,346.5,335,363.3,326.8,380.1z"/></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -2251,6 +2251,23 @@ PATH =
;;
;; Enable/Disable user statistics for nodeinfo if federation is enabled
; SHARE_USER_STATISTICS = true
;;
;; Maximum federation request and response size (MB)
; MAX_SIZE = 4
;;
;; WARNING: Changing the settings below can break federation.
;;
;; HTTP signature algorithms
; ALGORITHMS = rsa-sha256, rsa-sha512, ed25519
;;
;; HTTP signature digest algorithm
; DIGEST_ALGORITHM = SHA-256
;;
;; GET headers for federation requests
; GET_HEADERS = (request-target), Date
;;
;; POST headers for federation requests
; POST_HEADERS = (request-target), Date, Digest
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View file

@ -1090,6 +1090,14 @@ Task queue configuration has been moved to `queue.task`. However, the below conf
- `ENABLED`: **true**: Enable/Disable federation capabilities
- `SHARE_USER_STATISTICS`: **true**: Enable/Disable user statistics for nodeinfo if federation is enabled
- `MAX_SIZE`: **4**: Maximum federation request and response size (MB)
WARNING: Changing the settings below can break federation.
- `ALGORITHMS`: **rsa-sha256, rsa-sha512, ed25519**: HTTP signature algorithms
- `DIGEST_ALGORITHM`: **SHA-256**: HTTP signature digest algorithm
- `GET_HEADERS`: **(request-target), Date**: GET headers for federation requests
- `POST_HEADERS`: **(request-target), Date, Digest**: POST headers for federation requests
## Packages (`packages`)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 13 KiB

7
go.mod
View file

@ -28,10 +28,12 @@ require (
github.com/ethantkoenig/rupture v1.0.1
github.com/felixge/fgprof v0.9.2
github.com/gliderlabs/ssh v0.3.4
github.com/go-ap/activitypub v0.0.0-20220615144428-48208c70483b
github.com/go-ap/jsonld v0.0.0-20220615144122-1d862b15410d
github.com/go-chi/chi/v5 v5.0.7
github.com/go-chi/cors v1.2.1
github.com/go-enry/go-enry/v2 v2.8.2
github.com/go-fed/httpsig v1.1.0
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e
github.com/go-git/go-billy/v5 v5.3.1
github.com/go-git/go-git/v5 v5.4.3-0.20210630082519-b4368b2a2ca4
github.com/go-ldap/ldap/v3 v3.4.3
@ -83,6 +85,7 @@ require (
github.com/tstranex/u2f v1.0.0
github.com/unrolled/render v1.4.1
github.com/urfave/cli v1.22.9
github.com/valyala/fastjson v1.6.3
github.com/xanzy/go-gitlab v0.64.0
github.com/yohcop/openid-go v1.0.0
github.com/yuin/goldmark v1.4.12
@ -107,6 +110,7 @@ require (
require (
cloud.google.com/go v0.99.0 // indirect
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20200411073322-f0bcc40f0bf2 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5 // indirect
@ -160,6 +164,7 @@ require (
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/fullstorydev/grpcurl v1.8.1 // indirect
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
github.com/go-ap/errors v0.0.0-20220615144307-e8bc4a40ae9f // indirect
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
github.com/go-enry/go-oniguruma v1.2.1 // indirect
github.com/go-git/gcfg v1.5.0 // indirect

14
go.sum
View file

@ -69,6 +69,8 @@ contrib.go.opencensus.io/exporter/stackdriver v0.13.5/go.mod h1:aXENhDJ1Y4lIg4EU
contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20200411073322-f0bcc40f0bf2 h1:2OrsyJYZp7J6nyAsKi2q1SELYRaIc0aQmcQ/EQqPfk8=
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20200411073322-f0bcc40f0bf2/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb h1:Yy0Bxzc8R2wxiwXoG/rECGplJUSpXqCsog9PuJFgiHs=
gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb/go.mod h1:77TZu701zMXWJFvB8gvTbQ92zQ3DQq/H7l5wAEjQRKc=
gitea.com/go-chi/cache v0.0.0-20210110083709-82c4c9ce2d5e/go.mod h1:k2V/gPDEtXGjjMGuBJiapffAXTv76H4snSmlJRLUhH0=
@ -460,6 +462,12 @@ github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
github.com/go-ap/activitypub v0.0.0-20220615144428-48208c70483b h1:+RjYfEfoZdM3wHFs752dlOpGaoRhwRRyQxjajg08LcQ=
github.com/go-ap/activitypub v0.0.0-20220615144428-48208c70483b/go.mod h1:DE3vvc6Didgfd3k7M1Mos6qMDFNmMrxJmYVMHG9h9Io=
github.com/go-ap/errors v0.0.0-20220615144307-e8bc4a40ae9f h1:kJhGo4NApJP0Lt9lkJnfmuTnRWVFbCynY0kiTxpPUR4=
github.com/go-ap/errors v0.0.0-20220615144307-e8bc4a40ae9f/go.mod h1:KHkKFKZvc05lr79+RGoq/zG8YjWi3+FK60Bxd+mpCew=
github.com/go-ap/jsonld v0.0.0-20220615144122-1d862b15410d h1:Z/oRXMlZHjvjIqDma1FrIGL3iE5YL7MUI0bwYEZ6qbA=
github.com/go-ap/jsonld v0.0.0-20220615144122-1d862b15410d/go.mod h1:jyveZeGw5LaADntW+UEsMjl3IlIwk+DxlYNsbofQkGA=
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
@ -472,8 +480,8 @@ github.com/go-enry/go-enry/v2 v2.8.2 h1:uiGmC+3K8sVd/6DOe2AOJEOihJdqda83nPyJNtMR
github.com/go-enry/go-enry/v2 v2.8.2/go.mod h1:GVzIiAytiS5uT/QiuakK7TF1u4xDab87Y8V5EJRpsIQ=
github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo=
github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4=
github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e h1:oRq/fiirun5HqlEWMLIcDmLpIELlG4iGbd0s8iqgPi8=
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
@ -1507,6 +1515,8 @@ github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw=
github.com/urfave/cli v1.22.9/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fastjson v1.6.3 h1:tAKFnnwmeMGPbwJ7IwxcTPCNr3uIzoIj3/Fh90ra4xc=
github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
github.com/weppos/publicsuffix-go v0.13.1-0.20210123135404-5fd73613514e/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE=

View file

@ -0,0 +1,103 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package integrations
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"testing"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/activitypub"
"code.gitea.io/gitea/modules/setting"
ap "github.com/go-ap/activitypub"
"github.com/stretchr/testify/assert"
)
func TestActivityPubPerson(t *testing.T) {
onGiteaRun(t, func(*testing.T, *url.URL) {
setting.Federation.Enabled = true
defer func() {
setting.Federation.Enabled = false
}()
username := "user2"
req := NewRequestf(t, "GET", fmt.Sprintf("/api/v1/activitypub/user/%s", username))
resp := MakeRequest(t, req, http.StatusOK)
body := resp.Body.Bytes()
assert.Contains(t, string(body), "@context")
var person ap.Person
err := person.UnmarshalJSON(body)
assert.NoError(t, err)
assert.Equal(t, ap.PersonType, person.Type)
assert.Equal(t, username, person.PreferredUsername.String())
keyID := person.GetID().String()
assert.Regexp(t, fmt.Sprintf("activitypub/user/%s$", username), keyID)
assert.Regexp(t, fmt.Sprintf("activitypub/user/%s/outbox$", username), person.Outbox.GetID().String())
assert.Regexp(t, fmt.Sprintf("activitypub/user/%s/inbox$", username), person.Inbox.GetID().String())
pubKey := person.PublicKey
assert.NotNil(t, pubKey)
publicKeyID := keyID + "#main-key"
assert.Equal(t, pubKey.ID.String(), publicKeyID)
pubKeyPem := pubKey.PublicKeyPem
assert.NotNil(t, pubKeyPem)
assert.Regexp(t, "^-----BEGIN PUBLIC KEY-----", pubKeyPem)
})
}
func TestActivityPubMissingPerson(t *testing.T) {
onGiteaRun(t, func(*testing.T, *url.URL) {
setting.Federation.Enabled = true
defer func() {
setting.Federation.Enabled = false
}()
req := NewRequestf(t, "GET", "/api/v1/activitypub/user/nonexistentuser")
resp := MakeRequest(t, req, http.StatusNotFound)
assert.Contains(t, resp.Body.String(), "user redirect does not exist")
})
}
func TestActivityPubPersonInbox(t *testing.T) {
srv := httptest.NewServer(c)
defer srv.Close()
onGiteaRun(t, func(*testing.T, *url.URL) {
appURL := setting.AppURL
setting.Federation.Enabled = true
setting.AppURL = srv.URL
defer func() {
setting.Federation.Enabled = false
setting.Database.LogSQL = false
setting.AppURL = appURL
}()
username1 := "user1"
ctx := context.Background()
user1, err := user_model.GetUserByName(ctx, username1)
assert.NoError(t, err)
user1url := fmt.Sprintf("%s/api/v1/activitypub/user/%s#main-key", srv.URL, username1)
c, err := activitypub.NewClient(user1, user1url)
assert.NoError(t, err)
username2 := "user2"
user2inboxurl := fmt.Sprintf("%s/api/v1/activitypub/user/%s/inbox", srv.URL, username2)
// Signed request succeeds
resp, err := c.Post([]byte{}, user2inboxurl)
assert.NoError(t, err)
assert.Equal(t, http.StatusNoContent, resp.StatusCode)
// Unsigned request fails
req := NewRequest(t, "POST", user2inboxurl)
MakeRequest(t, req, http.StatusInternalServerError)
})
}

View file

@ -52,7 +52,7 @@ func TestWebfinger(t *testing.T) {
var jrd webfingerJRD
DecodeJSON(t, resp, &jrd)
assert.Equal(t, "acct:user2@"+appURL.Host, jrd.Subject)
assert.ElementsMatch(t, []string{user.HTMLURL()}, jrd.Aliases)
assert.ElementsMatch(t, []string{user.HTMLURL(), appURL.String() + "api/v1/activitypub/user/" + url.PathEscape(user.Name)}, jrd.Aliases)
req = NewRequest(t, "GET", fmt.Sprintf("/.well-known/webfinger?resource=acct:%s@%s", user.LowerName, "unknown.host"))
MakeRequest(t, req, http.StatusBadRequest)

View file

@ -22,14 +22,15 @@ type Type int
// Note: new type must append to the end of list to maintain compatibility.
const (
NoType Type = iota
Plain // 1
LDAP // 2
SMTP // 3
PAM // 4
DLDAP // 5
OAuth2 // 6
SSPI // 7
NoType Type = iota
Plain // 1
LDAP // 2
SMTP // 3
PAM // 4
DLDAP // 5
OAuth2 // 6
SSPI // 7
Federated // 8
)
// String returns the string name of the LoginType
@ -178,6 +179,11 @@ func (source *Source) IsSSPI() bool {
return source.Type == SSPI
}
// IsFederated returns true of this source is of the Federated type.
func (source *Source) IsFederated() bool {
return source.Type == Federated
}
// HasTLS returns true of this source supports TLS.
func (source *Source) HasTLS() bool {
hasTLSer, ok := source.Cfg.(HasTLSer)

View file

@ -17,7 +17,7 @@ var (
ErrNameEmpty = errors.New("Name is empty")
// AlphaDashDotPattern characters prohibited in a user name (anything except A-Za-z0-9_.-)
AlphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
AlphaDashDotPattern = regexp.MustCompile(`[^\w-\.@]`)
)
// ErrNameReserved represents a "reserved name" error.

View file

@ -0,0 +1,71 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package forgefed
import (
ap "github.com/go-ap/activitypub"
"github.com/valyala/fastjson"
)
const (
RepositoryType ap.ActivityVocabularyType = "Repository"
)
type Repository struct {
ap.Actor
// Team Collection of actors who have management/push access to the repository
Team ap.Item `jsonld:"team,omitempty"`
// Forks OrderedCollection of repositories that are forks of this repository
Forks ap.Item `jsonld:"forks,omitempty"`
}
// GetItemByType instantiates a new Repository object if the type matches
// otherwise it defaults to existing activitypub package typer function.
func GetItemByType(typ ap.ActivityVocabularyType) (ap.Item, error) {
if typ == RepositoryType {
return RepositoryNew(""), nil
}
return ap.GetItemByType(typ)
}
// RepositoryNew initializes a Repository type actor
func RepositoryNew(id ap.ID) *Repository {
a := ap.ActorNew(id, RepositoryType)
o := Repository{Actor: *a}
o.Type = RepositoryType
return &o
}
func (r Repository) MarshalJSON() ([]byte, error) {
b, err := r.Actor.MarshalJSON()
if len(b) == 0 || err != nil {
return make([]byte, 0), err
}
b = b[:len(b)-1]
if r.Team != nil {
ap.WriteItemJSONProp(&b, "team", r.Team)
}
if r.Forks != nil {
ap.WriteItemJSONProp(&b, "forks", r.Forks)
}
ap.Write(&b, '}')
return b, nil
}
func (r *Repository) UnmarshalJSON(data []byte) error {
p := fastjson.Parser{}
val, err := p.ParseBytes(data)
if err != nil {
return err
}
r.Team = ap.JSONGetItem(val, "team")
r.Forks = ap.JSONGetItem(val, "forks")
return ap.OnActor(&r.Actor, func(a *ap.Actor) error {
return ap.LoadActor(val, a)
})
}

View file

@ -0,0 +1,167 @@
package forgefed
import (
"encoding/json"
"fmt"
"reflect"
"testing"
ap "github.com/go-ap/activitypub"
)
func Test_GetItemByType(t *testing.T) {
type testtt struct {
typ ap.ActivityVocabularyType
want ap.Item
wantErr error
}
tests := map[string]testtt{
"invalid type": {
typ: ap.ActivityVocabularyType("invalidtype"),
wantErr: fmt.Errorf("empty ActivityStreams type"), // TODO(marius): this error message needs to be improved in go-ap/activitypub
},
"Repository": {
typ: RepositoryType,
want: new(Repository),
},
"Person - fall back": {
typ: ap.PersonType,
want: new(ap.Person),
},
"Question - fall back": {
typ: ap.QuestionType,
want: new(ap.Question),
},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
maybeRepository, err := GetItemByType(tt.typ)
if !reflect.DeepEqual(tt.wantErr, err) {
t.Errorf("GetItemByType() error = \"%+v\", wantErr = \"%+v\" when getting Item for type %q", tt.wantErr, err, tt.typ)
}
if reflect.TypeOf(tt.want) != reflect.TypeOf(maybeRepository) {
t.Errorf("Invalid type received %T, expected %T", maybeRepository, tt.want)
}
})
}
}
func Test_RepositoryMarshalJSON(t *testing.T) {
type testPair struct {
item Repository
want []byte
wantErr error
}
tests := map[string]testPair{
"empty": {
item: Repository{},
want: nil,
},
"with ID": {
item: Repository{
Actor: ap.Actor{
ID: "https://example.com/1",
},
Team: nil,
},
want: []byte(`{"id":"https://example.com/1"}`),
},
"with Team as IRI": {
item: Repository{
Team: ap.IRI("https://example.com/1"),
},
want: []byte(`{"team":"https://example.com/1"}`),
},
"with Team as IRIs": {
item: Repository{
Team: ap.ItemCollection{
ap.IRI("https://example.com/1"),
ap.IRI("https://example.com/2"),
},
},
want: []byte(`{"team":["https://example.com/1","https://example.com/2"]}`),
},
"with Team as Object": {
item: Repository{
Team: ap.Object{ID: "https://example.com/1"},
},
want: []byte(`{"team":{"id":"https://example.com/1"}}`),
},
"with Team as slice of Objects": {
item: Repository{
Team: ap.ItemCollection{
ap.Object{ID: "https://example.com/1"},
ap.Object{ID: "https://example.com/2"},
},
},
want: []byte(`{"team":[{"id":"https://example.com/1"},{"id":"https://example.com/2"}]}`),
},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
got, err := tt.item.MarshalJSON()
if (err != nil || tt.wantErr != nil) && tt.wantErr.Error() != err.Error() {
t.Errorf("MarshalJSON() error = \"%v\", wantErr \"%v\"", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("MarshalJSON() got = %q, want %q", got, tt.want)
}
})
}
}
func Test_RepositoryUnmarshalJSON(t *testing.T) {
type testPair struct {
data []byte
want *Repository
wantErr error
}
tests := map[string]testPair{
"nil": {
data: nil,
wantErr: fmt.Errorf("cannot parse JSON: %w", fmt.Errorf("cannot parse empty string; unparsed tail: %q", "")),
},
"empty": {
data: []byte{},
wantErr: fmt.Errorf("cannot parse JSON: %w", fmt.Errorf("cannot parse empty string; unparsed tail: %q", "")),
},
"with Type": {
data: []byte(`{"type":"Repository"}`),
want: &Repository{
Actor: ap.Actor{
Type: RepositoryType,
},
},
},
"with Type and ID": {
data: []byte(`{"id":"https://example.com/1","type":"Repository"}`),
want: &Repository{
Actor: ap.Actor{
ID: "https://example.com/1",
Type: RepositoryType,
},
},
},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
got := new(Repository)
err := got.UnmarshalJSON(tt.data)
if (err != nil || tt.wantErr != nil) && tt.wantErr.Error() != err.Error() {
t.Errorf("UnmarshalJSON() error = \"%v\", wantErr \"%v\"", err, tt.wantErr)
return
}
if tt.want != nil && !reflect.DeepEqual(got, tt.want) {
jGot, _ := json.Marshal(got)
jWant, _ := json.Marshal(tt.want)
t.Errorf("UnmarshalJSON() got = %s, want %s", jGot, jWant)
}
})
}
}

View file

@ -9,4 +9,8 @@ const (
SettingsKeyHiddenCommentTypes = "issue.hidden_comment_types"
// SettingsKeyDiffWhitespaceBehavior is the setting key for whitespace behavior of diff
SettingsKeyDiffWhitespaceBehavior = "diff.whitespace_behaviour"
// UserActivityPubPrivPem is user's private key
UserActivityPubPrivPem = "activitypub.priv_pem"
// UserActivityPubPubPem is user's public key
UserActivityPubPubPem = "activitypub.pub_pem"
)

View file

@ -0,0 +1,124 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package activitypub
import (
"bytes"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"net/http"
"strings"
"time"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/proxy"
"code.gitea.io/gitea/modules/setting"
"github.com/go-fed/httpsig"
)
const (
// ActivityStreamsContentType const
ActivityStreamsContentType = `application/ld+json; profile="https://www.w3.org/ns/activitystreams"`
httpsigExpirationTime = 60
)
// Gets the current time as an RFC 2616 formatted string
// RFC 2616 requires RFC 1123 dates but with GMT instead of UTC
func CurrentTime() string {
return strings.ReplaceAll(time.Now().UTC().Format(time.RFC1123), "UTC", "GMT")
}
func containsRequiredHTTPHeaders(method string, headers []string) error {
var hasRequestTarget, hasDate, hasDigest bool
for _, header := range headers {
hasRequestTarget = hasRequestTarget || header == httpsig.RequestTarget
hasDate = hasDate || header == "Date"
hasDigest = hasDigest || header == "Digest"
}
if !hasRequestTarget {
return fmt.Errorf("missing http header for %s: %s", method, httpsig.RequestTarget)
} else if !hasDate {
return fmt.Errorf("missing http header for %s: Date", method)
} else if !hasDigest && method != http.MethodGet {
return fmt.Errorf("missing http header for %s: Digest", method)
}
return nil
}
// Client struct
type Client struct {
client *http.Client
algs []httpsig.Algorithm
digestAlg httpsig.DigestAlgorithm
getHeaders []string
postHeaders []string
priv *rsa.PrivateKey
pubID string
}
// NewClient function
func NewClient(user *user_model.User, pubID string) (c *Client, err error) {
if err = containsRequiredHTTPHeaders(http.MethodGet, setting.Federation.GetHeaders); err != nil {
return
} else if err = containsRequiredHTTPHeaders(http.MethodPost, setting.Federation.PostHeaders); err != nil {
return
}
priv, err := GetPrivateKey(user)
if err != nil {
return
}
privPem, _ := pem.Decode([]byte(priv))
privParsed, err := x509.ParsePKCS1PrivateKey(privPem.Bytes)
if err != nil {
return
}
c = &Client{
client: &http.Client{
Transport: &http.Transport{
Proxy: proxy.Proxy(),
},
},
algs: setting.HttpsigAlgs,
digestAlg: httpsig.DigestAlgorithm(setting.Federation.DigestAlgorithm),
getHeaders: setting.Federation.GetHeaders,
postHeaders: setting.Federation.PostHeaders,
priv: privParsed,
pubID: pubID,
}
return
}
// NewRequest function
func (c *Client) NewRequest(b []byte, to string) (req *http.Request, err error) {
buf := bytes.NewBuffer(b)
req, err = http.NewRequest(http.MethodPost, to, buf)
if err != nil {
return
}
req.Header.Add("Content-Type", ActivityStreamsContentType)
req.Header.Add("Date", CurrentTime())
req.Header.Add("User-Agent", "Gitea/"+setting.AppVer)
signer, _, err := httpsig.NewSigner(c.algs, c.digestAlg, c.postHeaders, httpsig.Signature, httpsigExpirationTime)
if err != nil {
return
}
err = signer.SignRequest(c.priv, c.pubID, req, b)
return
}
// Post function
func (c *Client) Post(b []byte, to string) (resp *http.Response, err error) {
var req *http.Request
if req, err = c.NewRequest(b, to); err != nil {
return
}
resp, err = c.client.Do(req)
return
}

View file

@ -0,0 +1,49 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package activitypub
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"regexp"
"testing"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
_ "code.gitea.io/gitea/models" // https://discourse.gitea.io/t/testfixtures-could-not-clean-table-access-no-such-table-access/4137/4
"github.com/stretchr/testify/assert"
)
func TestActivityPubSignedPost(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
pubID := "https://example.com/pubID"
c, err := NewClient(user, pubID)
assert.NoError(t, err)
expected := "BODY"
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Regexp(t, regexp.MustCompile("^"+setting.Federation.DigestAlgorithm), r.Header.Get("Digest"))
assert.Contains(t, r.Header.Get("Signature"), pubID)
assert.Equal(t, r.Header.Get("Content-Type"), ActivityStreamsContentType)
body, err := io.ReadAll(r.Body)
assert.NoError(t, err)
assert.Equal(t, expected, string(body))
fmt.Fprintf(w, expected)
}))
defer srv.Close()
r, err := c.Post([]byte(expected), srv.URL)
assert.NoError(t, err)
defer r.Body.Close()
body, err := io.ReadAll(r.Body)
assert.NoError(t, err)
assert.Equal(t, expected, string(body))
}

View file

@ -0,0 +1,46 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package activitypub
import (
"context"
"strings"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
ap "github.com/go-ap/activitypub"
)
func Follow(ctx context.Context, activity ap.Follow) {
actorIRI := activity.Actor.GetID()
objectIRI := activity.Object.GetID()
actorIRISplit := strings.Split(actorIRI.String(), "/")
objectIRISplit := strings.Split(objectIRI.String(), "/")
actorName := actorIRISplit[len(actorIRISplit)-1] + "@" + actorIRISplit[2]
objectName := objectIRISplit[len(objectIRISplit)-1]
err := FederatedUserNew(actorName, actorIRI)
if err != nil {
log.Warn("Couldn't create new user", err)
}
actorUser, err := user_model.GetUserByName(ctx, actorName)
if err != nil {
log.Warn("Couldn't find actor", err)
}
objectUser, err := user_model.GetUserByName(ctx, objectName)
if err != nil {
log.Warn("Couldn't find object", err)
}
user_model.FollowUser(actorUser.ID, objectUser.ID)
accept := ap.AcceptNew(objectIRI, activity)
accept.Actor = ap.Person{ID: objectIRI}
accept.To = ap.ItemCollection{ap.IRI(actorIRI.String() + "/inbox")}
accept.Object = activity
Send(objectUser, accept)
}

View file

@ -0,0 +1,18 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package activitypub
import (
"path/filepath"
"testing"
"code.gitea.io/gitea/models/unittest"
)
func TestMain(m *testing.M) {
unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: filepath.Join("..", ".."),
})
}

View file

@ -0,0 +1,59 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package activitypub
import (
"fmt"
"io"
"net/http"
"net/url"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
ap "github.com/go-ap/activitypub"
)
func Fetch(iri *url.URL) (b []byte, err error) {
req := httplib.NewRequest(iri.String(), http.MethodGet)
req.Header("Accept", ActivityStreamsContentType)
req.Header("User-Agent", "Gitea/"+setting.AppVer)
resp, err := req.Response()
if err != nil {
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
err = fmt.Errorf("url IRI fetch [%s] failed with status (%d): %s", iri, resp.StatusCode, resp.Status)
return
}
b, err = io.ReadAll(io.LimitReader(resp.Body, setting.Federation.MaxSize))
return
}
func Send(user *user_model.User, activity *ap.Activity) {
body, err := activity.MarshalJSON()
if err != nil {
return
}
var jsonmap map[string]interface{}
err = json.Unmarshal(body, &jsonmap)
if err != nil {
return
}
jsonmap["@context"] = "https://www.w3.org/ns/activitystreams"
body, _ = json.Marshal(jsonmap)
for _, to := range activity.To {
client, _ := NewClient(user, setting.AppURL+"api/v1/activitypub/user/"+user.Name+"#main-key")
resp, _ := client.Post(body, to.GetID().String())
respBody, _ := io.ReadAll(io.LimitReader(resp.Body, setting.Federation.MaxSize))
log.Debug(string(respBody))
}
}

View file

@ -0,0 +1,22 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package activitypub
import (
"code.gitea.io/gitea/models/auth"
user_model "code.gitea.io/gitea/models/user"
ap "github.com/go-ap/activitypub"
)
func FederatedUserNew(name string, IRI ap.IRI) error {
user := &user_model.User{
Name: name,
Email: name,
LoginType: auth.Federated,
Website: IRI.String(),
}
return user_model.CreateUser(user)
}

View file

@ -0,0 +1,45 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package activitypub
import (
user_model "code.gitea.io/gitea/models/user"
)
// GetKeyPair function returns a user's private and public keys
func GetKeyPair(user *user_model.User) (pub, priv string, err error) {
var settings map[string]*user_model.Setting
settings, err = user_model.GetUserSettings(user.ID, []string{user_model.UserActivityPubPrivPem, user_model.UserActivityPubPubPem})
if err != nil {
return
} else if len(settings) == 0 {
if priv, pub, err = GenerateKeyPair(); err != nil {
return
}
if err = user_model.SetUserSetting(user.ID, user_model.UserActivityPubPrivPem, priv); err != nil {
return
}
if err = user_model.SetUserSetting(user.ID, user_model.UserActivityPubPubPem, pub); err != nil {
return
}
return
} else {
priv = settings[user_model.UserActivityPubPrivPem].SettingValue
pub = settings[user_model.UserActivityPubPubPem].SettingValue
return
}
}
// GetPublicKey function returns a user's public key
func GetPublicKey(user *user_model.User) (pub string, err error) {
pub, _, err = GetKeyPair(user)
return
}
// GetPrivateKey function returns a user's private key
func GetPrivateKey(user *user_model.User) (priv string, err error) {
_, priv, err = GetKeyPair(user)
return
}

View file

@ -0,0 +1,29 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package activitypub
import (
"testing"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
_ "code.gitea.io/gitea/models" // https://discourse.gitea.io/t/testfixtures-could-not-clean-table-access-no-such-table-access/4137/4
"github.com/stretchr/testify/assert"
)
func TestUserSettings(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
pub, priv, err := GetKeyPair(user1)
assert.NoError(t, err)
pub1, err := GetPublicKey(user1)
assert.NoError(t, err)
assert.Equal(t, pub, pub1)
priv1, err := GetPrivateKey(user1)
assert.NoError(t, err)
assert.Equal(t, priv, priv1)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 521 B

After

Width:  |  Height:  |  Size: 287 B

View file

@ -4,21 +4,49 @@
package setting
import "code.gitea.io/gitea/modules/log"
import (
"code.gitea.io/gitea/modules/log"
"github.com/go-fed/httpsig"
)
// Federation settings
var (
Federation = struct {
Enabled bool
ShareUserStatistics bool
MaxSize int64
Algorithms []string
DigestAlgorithm string
GetHeaders []string
PostHeaders []string
}{
Enabled: true,
ShareUserStatistics: true,
MaxSize: 4,
Algorithms: []string{"rsa-sha256", "rsa-sha512", "ed25519"},
DigestAlgorithm: "SHA-256",
GetHeaders: []string{"(request-target)", "Date"},
PostHeaders: []string{"(request-target)", "Date", "Digest"},
}
)
// Constant slice of httpsig algorithm objects
var HttpsigAlgs []httpsig.Algorithm
func newFederationService() {
if err := Cfg.Section("federation").MapTo(&Federation); err != nil {
log.Fatal("Failed to map Federation settings: %v", err)
} else if !httpsig.IsSupportedDigestAlgorithm(Federation.DigestAlgorithm) {
log.Fatal("unsupported digest algorithm: %s", Federation.DigestAlgorithm)
return
}
// Get MaxSize in bytes instead of MiB
Federation.MaxSize = 1 << 20 * Federation.MaxSize
HttpsigAlgs = make([]httpsig.Algorithm, len(Federation.Algorithms))
for i, alg := range Federation.Algorithms {
HttpsigAlgs[i] = httpsig.Algorithm(alg)
}
}

View file

@ -0,0 +1,10 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package structs
// ActivityPub type
type ActivityPub struct {
Context string `json:"@context"`
}

View file

@ -117,7 +117,7 @@ not_found = The target couldn't be found.
network_error = Network error
[startpage]
app_desc = A painless, self-hosted Git service
app_desc = The world's first ActivityPub-federated Git server!
install = Easy to install
install_desc = Simply <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-binary/">run the binary</a> for your platform, ship it with <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a>, or get it <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-package/">packaged</a>.
platform = Cross-platform

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5 KiB

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 792 B

After

Width:  |  Height:  |  Size: 791 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View file

@ -1,14 +1 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 520 520" style="enable-background:new 0 0 520 520;" xml:space="preserve">
<path d="M13.7,11.9v496.2h35.7V520H0V0h49.4v11.9H13.7z"/>
<path d="M166.3,169.2v25.1h0.7c6.7-9.6,14.8-17,24.2-22.2c9.4-5.3,20.3-7.9,32.5-7.9c11.7,0,22.4,2.3,32.1,6.8
c9.7,4.5,17,12.6,22.1,24c5.5-8.1,13-15.3,22.4-21.5c9.4-6.2,20.6-9.3,33.5-9.3c9.8,0,18.9,1.2,27.3,3.6c8.4,2.4,15.5,6.2,21.5,11.5
c6,5.3,10.6,12.1,14,20.6c3.3,8.5,5,18.7,5,30.7v124.1h-50.9V249.6c0-6.2-0.2-12.1-0.7-17.6c-0.5-5.5-1.8-10.3-3.9-14.3
c-2.2-4.1-5.3-7.3-9.5-9.7c-4.2-2.4-9.9-3.6-17-3.6c-7.2,0-13,1.4-17.4,4.1c-4.4,2.8-7.9,6.3-10.4,10.8c-2.5,4.4-4.2,9.4-5,15.1
c-0.8,5.6-1.3,11.3-1.3,17v103.3h-50.9v-104c0-5.5-0.1-10.9-0.4-16.3c-0.2-5.4-1.3-10.3-3.1-14.9c-1.8-4.5-4.8-8.2-9-10.9
c-4.2-2.7-10.3-4.1-18.5-4.1c-2.4,0-5.6,0.5-9.5,1.6c-3.9,1.1-7.8,3.1-11.5,6.1c-3.7,3-6.9,7.3-9.5,12.9c-2.6,5.6-3.9,13-3.9,22.1
v107.6h-50.9V169.2H166.3z"/>
<path d="M506.3,508.1V11.9h-35.7V0H520v520h-49.4v-11.9H506.3z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" x="0" y="0" version="1.1" viewBox="0 0 520 520" xml:space="preserve" style="enable-background:new 0 0 520 520"><path d="M13.7,11.9v496.2h35.7V520H0V0h49.4v11.9H13.7z"/><path d="M166.3,169.2v25.1h0.7c6.7-9.6,14.8-17,24.2-22.2c9.4-5.3,20.3-7.9,32.5-7.9c11.7,0,22.4,2.3,32.1,6.8 c9.7,4.5,17,12.6,22.1,24c5.5-8.1,13-15.3,22.4-21.5c9.4-6.2,20.6-9.3,33.5-9.3c9.8,0,18.9,1.2,27.3,3.6c8.4,2.4,15.5,6.2,21.5,11.5 c6,5.3,10.6,12.1,14,20.6c3.3,8.5,5,18.7,5,30.7v124.1h-50.9V249.6c0-6.2-0.2-12.1-0.7-17.6c-0.5-5.5-1.8-10.3-3.9-14.3 c-2.2-4.1-5.3-7.3-9.5-9.7c-4.2-2.4-9.9-3.6-17-3.6c-7.2,0-13,1.4-17.4,4.1c-4.4,2.8-7.9,6.3-10.4,10.8c-2.5,4.4-4.2,9.4-5,15.1 c-0.8,5.6-1.3,11.3-1.3,17v103.3h-50.9v-104c0-5.5-0.1-10.9-0.4-16.3c-0.2-5.4-1.3-10.3-3.1-14.9c-1.8-4.5-4.8-8.2-9-10.9 c-4.2-2.7-10.3-4.1-18.5-4.1c-2.4,0-5.6,0.5-9.5,1.6c-3.9,1.1-7.8,3.1-11.5,6.1c-3.7,3-6.9,7.3-9.5,12.9c-2.6,5.6-3.9,13-3.9,22.1 v107.6h-50.9V169.2H166.3z"/><path d="M506.3,508.1V11.9h-35.7V0H520v520h-49.4v-11.9H506.3z"/></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View file

@ -1,11 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
width="40"
height="40"
viewBox="0 0 40 40">
<path
d="M 1.5006714,23.536225 6.8925879,18.994244 14.585721,26.037937 34.019683,4.5410479 38.499329,9.2235032 14.585721,35.458952 z"
id="path4"
style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1.25402856;stroke-opacity:1" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path id="path4" d="M 1.5006714,23.536225 6.8925879,18.994244 14.585721,26.037937 34.019683,4.5410479 38.499329,9.2235032 14.585721,35.458952 z" style="fill:#ff0;fill-opacity:1;stroke:#000;stroke-width:1.25402856;stroke-opacity:1"/></svg>

Before

Width:  |  Height:  |  Size: 415 B

After

Width:  |  Height:  |  Size: 321 B

View file

@ -1,16 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
height="40"
width="40"
viewBox="0 0 40 40">
<rect
style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
width="33.76017"
height="33.76017"
x="3.119915"
y="3.119915" />
<path
d="m 20.677967,8.54499 c -7.342801,0 -13.295293,4.954293 -13.295293,11.065751 0,2.088793 0.3647173,3.484376 1.575539,5.150563 L 6.0267418,31.45501 13.560595,29.011117 c 2.221262,1.387962 4.125932,1.665377 7.117372,1.665377 7.3428,0 13.295291,-4.954295 13.295291,-11.065753 0,-6.111458 -5.952491,-11.065751 -13.295291,-11.065751 z"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.93031836;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><rect style="fill:#ff0;fill-opacity:1;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" width="33.76" height="33.76" x="3.12" y="3.12"/><path d="m 20.677967,8.54499 c -7.342801,0 -13.295293,4.954293 -13.295293,11.065751 0,2.088793 0.3647173,3.484376 1.575539,5.150563 L 6.0267418,31.45501 13.560595,29.011117 c 2.221262,1.387962 4.125932,1.665377 7.117372,1.665377 7.3428,0 13.295291,-4.954295 13.295291,-11.065753 0,-6.111458 -5.952491,-11.065751 -13.295291,-11.065751 z" style="fill:#fff;fill-opacity:1;stroke:#000;stroke-width:.93031836;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/></svg>

Before

Width:  |  Height:  |  Size: 883 B

After

Width:  |  Height:  |  Size: 745 B

View file

@ -1,26 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
width="40"
height="40"
viewBox="0 0 40 40">
<g
transform="translate(0,-60)"
id="layer1">
<rect
width="36.460953"
height="34.805603"
x="1.7695236"
y="62.597198"
style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.30826771;stroke-opacity:1" />
<g
transform="matrix(0.88763677,0,0,0.88763677,2.2472646,8.9890584)">
<path
d="M 20,64.526342 C 11.454135,64.526342 4.5263421,71.454135 4.5263421,80 4.5263421,88.545865 11.454135,95.473658 20,95.473658 28.545865,95.473658 35.473658,88.545865 35.473658,80 35.473658,71.454135 28.545865,64.526342 20,64.526342 z m -0.408738,9.488564 c 3.527079,0 6.393832,2.84061 6.393832,6.335441 0,3.494831 -2.866753,6.335441 -6.393832,6.335441 -3.527079,0 -6.393832,-2.84061 -6.393832,-6.335441 0,-3.494831 2.866753,-6.335441 6.393832,-6.335441 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.02768445;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
d="m 7.2335209,71.819938 4.9702591,4.161823 c -1.679956,2.581606 -1.443939,6.069592 0.159325,8.677725 l -5.1263071,3.424463 c 0.67516,1.231452 3.0166401,3.547686 4.2331971,4.194757 l 3.907728,-4.567277 c 2.541952,1.45975 5.730694,1.392161 8.438683,-0.12614 l 3.469517,6.108336 c 1.129779,-0.44367 4.742234,-3.449633 5.416358,-5.003859 l -5.46204,-4.415541 c 1.44319,-2.424098 1.651175,-5.267515 0.557303,-7.748623 l 5.903195,-3.833951 C 33.14257,71.704996 30.616217,69.018606 29.02952,67.99296 l -4.118813,4.981678 C 22.411934,71.205099 18.900853,70.937534 16.041319,72.32916 l -3.595408,-5.322091 c -1.345962,0.579488 -4.1293881,2.921233 -5.2123901,4.812869 z m 8.1010311,3.426672 c 2.75284,-2.446266 6.769149,-2.144694 9.048998,0.420874 2.279848,2.56557 2.113919,6.596919 -0.638924,9.043185 -2.752841,2.446267 -6.775754,2.13726 -9.055604,-0.428308 -2.279851,-2.565568 -2.107313,-6.589485 0.64553,-9.035751 z"
style="fill:#000000;fill-opacity:1;stroke:none" />
</g>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><g id="layer1" transform="translate(0,-60)"><rect width="36.461" height="34.806" x="1.77" y="62.597" style="fill:#ff0;fill-opacity:1;fill-rule:evenodd;stroke:#000;stroke-width:1.30826771;stroke-opacity:1"/><g><path d="M 20,64.526342 C 11.454135,64.526342 4.5263421,71.454135 4.5263421,80 4.5263421,88.545865 11.454135,95.473658 20,95.473658 28.545865,95.473658 35.473658,88.545865 35.473658,80 35.473658,71.454135 28.545865,64.526342 20,64.526342 z m -0.408738,9.488564 c 3.527079,0 6.393832,2.84061 6.393832,6.335441 0,3.494831 -2.866753,6.335441 -6.393832,6.335441 -3.527079,0 -6.393832,-2.84061 -6.393832,-6.335441 0,-3.494831 2.866753,-6.335441 6.393832,-6.335441 z" transform="matrix(0.88763677,0,0,0.88763677,2.2472646,8.9890584)" style="fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:#000;stroke-width:1.02768445;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/><path d="m 7.2335209,71.819938 4.9702591,4.161823 c -1.679956,2.581606 -1.443939,6.069592 0.159325,8.677725 l -5.1263071,3.424463 c 0.67516,1.231452 3.0166401,3.547686 4.2331971,4.194757 l 3.907728,-4.567277 c 2.541952,1.45975 5.730694,1.392161 8.438683,-0.12614 l 3.469517,6.108336 c 1.129779,-0.44367 4.742234,-3.449633 5.416358,-5.003859 l -5.46204,-4.415541 c 1.44319,-2.424098 1.651175,-5.267515 0.557303,-7.748623 l 5.903195,-3.833951 C 33.14257,71.704996 30.616217,69.018606 29.02952,67.99296 l -4.118813,4.981678 C 22.411934,71.205099 18.900853,70.937534 16.041319,72.32916 l -3.595408,-5.322091 c -1.345962,0.579488 -4.1293881,2.921233 -5.2123901,4.812869 z m 8.1010311,3.426672 c 2.75284,-2.446266 6.769149,-2.144694 9.048998,0.420874 2.279848,2.56557 2.113919,6.596919 -0.638924,9.043185 -2.752841,2.446267 -6.775754,2.13726 -9.055604,-0.428308 -2.279851,-2.565568 -2.107313,-6.589485 0.64553,-9.035751 z" transform="matrix(0.88763677,0,0,0.88763677,2.2472646,8.9890584)" style="fill:#000;fill-opacity:1;stroke:none"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,10 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
viewBox="0 0 64 64">
<path
d="M 32.003143,1.4044602 57.432701,62.632577 6.5672991,62.627924 z"
style="fill:#ffff00;fill-opacity:0.94117647;fill-rule:nonzero;stroke:#000000;stroke-width:1.00493038;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><path d="M 32.003143,1.4044602 57.432701,62.632577 6.5672991,62.627924 z" style="fill:#ff0;fill-opacity:.94117647;fill-rule:nonzero;stroke:#000;stroke-width:1.00493038;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/></svg>

Before

Width:  |  Height:  |  Size: 408 B

After

Width:  |  Height:  |  Size: 318 B

View file

@ -1,11 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
viewBox="0 0 64 64">
<path
d="M 25.470843,9.4933766 C 25.30219,12.141818 30.139101,14.445969 34.704831,13.529144 40.62635,12.541995 41.398833,7.3856498 35.97505,5.777863 31.400921,4.1549155 25.157674,6.5445892 25.470843,9.4933766 z M 4.5246282,17.652051 C 4.068249,11.832873 9.2742983,5.9270407 18.437379,3.0977088 29.751911,-0.87185184 45.495663,1.4008022 53.603953,7.1104009 c 9.275765,6.1889221 7.158128,16.2079421 -3.171076,21.5939521 -1.784316,1.635815 -6.380222,1.21421 -7.068351,3.186186 -1.04003,0.972427 -1.288046,2.050158 -1.232864,3.168203 1.015111,2.000108 -3.831548,1.633216 -3.270553,3.759574 0.589477,5.264544 -0.179276,10.53738 -0.362842,15.806257 -0.492006,2.184998 1.163456,4.574232 -0.734888,6.610642 -2.482919,2.325184 -7.30604,2.189143 -9.193497,-0.274767 -2.733688,-1.740626 -8.254447,-3.615254 -6.104247,-6.339626 3.468112,-1.708686 -2.116197,-3.449897 0.431242,-5.080274 5.058402,-1.39256 -2.393215,-2.304318 -0.146889,-4.334645 3.069198,-0.977415 2.056986,-2.518352 -0.219121,-3.540397 1.876567,-1.807151 1.484149,-4.868919 -2.565455,-5.942205 0.150866,-1.805474 2.905737,-4.136876 -1.679967,-5.20493 C 10.260902,27.882167 4.6872697,22.95045 4.5245945,17.652051 z"
id="path604"
style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1.72665179;stroke-opacity:1" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><path id="path604" d="M 25.470843,9.4933766 C 25.30219,12.141818 30.139101,14.445969 34.704831,13.529144 40.62635,12.541995 41.398833,7.3856498 35.97505,5.777863 31.400921,4.1549155 25.157674,6.5445892 25.470843,9.4933766 z M 4.5246282,17.652051 C 4.068249,11.832873 9.2742983,5.9270407 18.437379,3.0977088 29.751911,-0.87185184 45.495663,1.4008022 53.603953,7.1104009 c 9.275765,6.1889221 7.158128,16.2079421 -3.171076,21.5939521 -1.784316,1.635815 -6.380222,1.21421 -7.068351,3.186186 -1.04003,0.972427 -1.288046,2.050158 -1.232864,3.168203 1.015111,2.000108 -3.831548,1.633216 -3.270553,3.759574 0.589477,5.264544 -0.179276,10.53738 -0.362842,15.806257 -0.492006,2.184998 1.163456,4.574232 -0.734888,6.610642 -2.482919,2.325184 -7.30604,2.189143 -9.193497,-0.274767 -2.733688,-1.740626 -8.254447,-3.615254 -6.104247,-6.339626 3.468112,-1.708686 -2.116197,-3.449897 0.431242,-5.080274 5.058402,-1.39256 -2.393215,-2.304318 -0.146889,-4.334645 3.069198,-0.977415 2.056986,-2.518352 -0.219121,-3.540397 1.876567,-1.807151 1.484149,-4.868919 -2.565455,-5.942205 0.150866,-1.805474 2.905737,-4.136876 -1.679967,-5.20493 C 10.260902,27.882167 4.6872697,22.95045 4.5245945,17.652051 z" style="fill:#ff0;fill-opacity:1;stroke:#000;stroke-width:1.72665179;stroke-opacity:1"/></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -1,11 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
viewBox="0 0 64 64">
<path
d="M 32.003143,10.913072 57.432701,53.086929 6.567299,53.083723 z"
id="path2985"
style="fill:#ffff00;fill-opacity:0.94117647;fill-rule:nonzero;stroke:#000000;stroke-width:0.83403099;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><path id="path2985" d="M 32.003143,10.913072 57.432701,53.086929 6.567299,53.083723 z" style="fill:#ff0;fill-opacity:.94117647;fill-rule:nonzero;stroke:#000;stroke-width:.83403099;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/></svg>

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 330 B

View file

@ -1,7 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
width="40"
height="40"
viewBox="0 0 40 40">
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"/>

Before

Width:  |  Height:  |  Size: 158 B

After

Width:  |  Height:  |  Size: 84 B

View file

@ -1,42 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
width="40"
height="40"
viewBox="0 0 40 40">
<rect
width="36.075428"
height="31.096582"
x="1.962286"
y="4.4517088"
id="rect4"
style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.23004246;stroke-opacity:1" />
<rect
width="27.96859"
height="1.5012145"
x="6.0157046"
y="10.285"
id="rect6"
style="fill:#000000;fill-opacity:1;stroke:none" />
<rect
width="27.96859"
height="0.85783684"
x="6.0157056"
y="23.21689"
id="rect8"
style="fill:#000000;fill-opacity:1;stroke:none" />
<rect
width="27.96859"
height="0.85783684"
x="5.8130345"
y="28.964394"
id="rect10"
style="fill:#000000;fill-opacity:1;stroke:none" />
<rect
width="27.96859"
height="0.85783684"
x="6.0157046"
y="17.426493"
id="rect12"
style="fill:#000000;fill-opacity:1;stroke:none" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><rect id="rect4" width="36.075" height="31.097" x="1.962" y="4.452" style="fill:#ff0;fill-opacity:1;fill-rule:evenodd;stroke:#000;stroke-width:1.23004246;stroke-opacity:1"/><rect id="rect6" width="27.969" height="1.501" x="6.016" y="10.285" style="fill:#000;fill-opacity:1;stroke:none"/><rect id="rect8" width="27.969" height=".858" x="6.016" y="23.217" style="fill:#000;fill-opacity:1;stroke:none"/><rect id="rect10" width="27.969" height=".858" x="5.813" y="28.964" style="fill:#000;fill-opacity:1;stroke:none"/><rect id="rect12" width="27.969" height=".858" x="6.016" y="17.426" style="fill:#000;fill-opacity:1;stroke:none"/></svg>

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 717 B

View file

@ -1,16 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
width="40"
height="40"
viewBox="0 0 40 40">
<rect
width="33.76017"
height="33.76017"
x="3.119915"
y="3.119915"
style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
d="m 17.692678,34.50206 0,-16.182224 c -1.930515,-0.103225 -3.455824,-0.730383 -4.57593,-1.881473 -1.12011,-1.151067 -1.680164,-2.619596 -1.680164,-4.405591 0,-1.992435 0.621995,-3.5796849 1.865988,-4.7617553 1.243989,-1.1820288 3.06352,-1.7730536 5.458598,-1.7730764 l 9.802246,0 0,2.6789711 -2.229895,0 0,26.3251486 -2.632515,0 0,-26.3251486 -3.45324,0 0,26.3251486 z"
style="font-size:29.42051125px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.07795751;stroke-opacity:1;font-family:Arial;-inkscape-font-specification:Arial" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><rect width="33.76" height="33.76" x="3.12" y="3.12" style="fill:#ff0;fill-opacity:1;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/><path d="m 17.692678,34.50206 0,-16.182224 c -1.930515,-0.103225 -3.455824,-0.730383 -4.57593,-1.881473 -1.12011,-1.151067 -1.680164,-2.619596 -1.680164,-4.405591 0,-1.992435 0.621995,-3.5796849 1.865988,-4.7617553 1.243989,-1.1820288 3.06352,-1.7730536 5.458598,-1.7730764 l 9.802246,0 0,2.6789711 -2.229895,0 0,26.3251486 -2.632515,0 0,-26.3251486 -3.45324,0 0,26.3251486 z" style="font-size:29.42051125px;font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0;word-spacing:0;writing-mode:lr-tb;text-anchor:start;fill:#fff;fill-opacity:1;stroke:#000;stroke-width:1.07795751;stroke-opacity:1;font-family:Arial;-inkscape-font-specification:Arial"/></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 998 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -0,0 +1,278 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package activitypub
import (
"io"
"net/http"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/forgefed"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/activitypub"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/api/v1/utils"
ap "github.com/go-ap/activitypub"
)
// Person function returns the Person actor for a user
func Person(ctx *context.APIContext) {
// swagger:operation GET /activitypub/user/{username} activitypub activitypubPerson
// ---
// summary: Returns the Person actor for a user
// produces:
// - application/activity+json
// parameters:
// - name: username
// in: path
// description: username of the user
// type: string
// required: true
// responses:
// "200":
// "$ref": "#/responses/ActivityPub"
link := strings.TrimSuffix(setting.AppURL, "/") + "/api/v1/activitypub/user/" + ctx.ContextUser.Name
person := ap.PersonNew(ap.IRI(link))
person.Name = ap.NaturalLanguageValuesNew()
err := person.Name.Set("en", ap.Content(ctx.ContextUser.FullName))
if err != nil {
ctx.Error(http.StatusInternalServerError, "Set Name", err)
return
}
person.PreferredUsername = ap.NaturalLanguageValuesNew()
err = person.PreferredUsername.Set("en", ap.Content(ctx.ContextUser.Name))
if err != nil {
ctx.Error(http.StatusInternalServerError, "Set PreferredUsername", err)
return
}
person.URL = ap.IRI(ctx.ContextUser.HTMLURL())
person.Icon = ap.Image{
Type: ap.ImageType,
MediaType: "image/png",
URL: ap.IRI(ctx.ContextUser.AvatarLink()),
}
person.Inbox = ap.IRI(link + "/inbox")
person.Outbox = ap.IRI(link + "/outbox")
person.Following = ap.IRI(link + "/following")
person.Followers = ap.IRI(link + "/followers")
person.Liked = ap.IRI(link + "/liked")
person.PublicKey.ID = ap.IRI(link + "#main-key")
person.PublicKey.Owner = ap.IRI(link)
publicKeyPem, err := activitypub.GetPublicKey(ctx.ContextUser)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetPublicKey", err)
return
}
person.PublicKey.PublicKeyPem = publicKeyPem
response(ctx, person)
}
// PersonInbox function handles the incoming data for a user inbox
func PersonInbox(ctx *context.APIContext) {
// swagger:operation POST /activitypub/user/{username}/inbox activitypub activitypubPersonInbox
// ---
// summary: Send to the inbox
// produces:
// - application/activity+json
// parameters:
// - name: username
// in: path
// description: username of the user
// type: string
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
body, err := io.ReadAll(io.LimitReader(ctx.Req.Body, setting.Federation.MaxSize))
if err != nil {
ctx.Error(http.StatusInternalServerError, "Error reading request body", err)
}
var activity ap.Activity
activity.UnmarshalJSON(body)
if activity.Type == ap.FollowType {
activitypub.Follow(ctx, activity)
} else {
log.Warn("ActivityStreams type not supported", activity)
ctx.PlainText(http.StatusNotImplemented, "ActivityStreams type not supported")
return
}
ctx.Status(http.StatusNoContent)
}
// PersonOutbox function returns the user's Outbox OrderedCollection
func PersonOutbox(ctx *context.APIContext) {
// swagger:operation GET /activitypub/user/{username}/outbox activitypub activitypubPersonOutbox
// ---
// summary: Returns the Outbox OrderedCollection
// produces:
// - application/activity+json
// parameters:
// - name: username
// in: path
// description: username of the user
// type: string
// required: true
// responses:
// "200":
// "$ref": "#/responses/ActivityPub"
link := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(ctx.Req.URL.EscapedPath(), "/")
feed, err := models.GetFeeds(ctx, models.GetFeedsOptions{
RequestedUser: ctx.ContextUser,
Actor: ctx.ContextUser,
IncludePrivate: false,
OnlyPerformedBy: true,
IncludeDeleted: false,
Date: ctx.FormString("date"),
})
if err != nil {
ctx.Error(http.StatusInternalServerError, "Couldn't fetch outbox", err)
}
outbox := ap.OrderedCollectionNew(ap.IRI(link))
for _, action := range feed {
/*if action.OpType == ExampleType {
activity := ap.ExampleNew()
outbox.OrderedItems.Append(activity)
}*/
log.Debug(action.Content)
}
outbox.TotalItems = uint(len(outbox.OrderedItems))
response(ctx, outbox)
}
// PersonFollowing function returns the user's Following Collection
func PersonFollowing(ctx *context.APIContext) {
// swagger:operation GET /activitypub/user/{username}/following activitypub activitypubPersonFollowing
// ---
// summary: Returns the Following Collection
// produces:
// - application/activity+json
// parameters:
// - name: username
// in: path
// description: username of the user
// type: string
// required: true
// responses:
// "200":
// "$ref": "#/responses/ActivityPub"
link := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(ctx.Req.URL.EscapedPath(), "/")
users, err := user_model.GetUserFollowing(ctx.ContextUser, utils.GetListOptions(ctx))
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserFollowing", err)
return
}
following := ap.OrderedCollectionNew(ap.IRI(link))
following.TotalItems = uint(len(users))
for _, user := range users {
// TODO: handle non-Federated users
person := ap.PersonNew(ap.IRI(user.Website))
following.OrderedItems.Append(person)
}
response(ctx, following)
}
// PersonFollowers function returns the user's Followers Collection
func PersonFollowers(ctx *context.APIContext) {
// swagger:operation GET /activitypub/user/{username}/followers activitypub activitypubPersonFollowers
// ---
// summary: Returns the Followers Collection
// produces:
// - application/activity+json
// parameters:
// - name: username
// in: path
// description: username of the user
// type: string
// required: true
// responses:
// "200":
// "$ref": "#/responses/ActivityPub"
link := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(ctx.Req.URL.EscapedPath(), "/")
users, err := user_model.GetUserFollowers(ctx.ContextUser, utils.GetListOptions(ctx))
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserFollowers", err)
return
}
followers := ap.OrderedCollectionNew(ap.IRI(link))
followers.TotalItems = uint(len(users))
for _, user := range users {
person := ap.PersonNew(ap.IRI(user.Website))
followers.OrderedItems.Append(person)
}
response(ctx, followers)
}
// PersonLiked function returns the user's Liked Collection
func PersonLiked(ctx *context.APIContext) {
// swagger:operation GET /activitypub/user/{username}/followers activitypub activitypubPersonLiked
// ---
// summary: Returns the Liked Collection
// produces:
// - application/activity+json
// parameters:
// - name: username
// in: path
// description: username of the user
// type: string
// required: true
// responses:
// "200":
// "$ref": "#/responses/ActivityPub"
link := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(ctx.Req.URL.EscapedPath(), "/")
repos, count, err := repo_model.SearchRepository(&repo_model.SearchRepoOptions{
Actor: ctx.Doer,
Private: ctx.IsSigned,
StarredByID: ctx.ContextUser.ID,
})
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserStarred", err)
return
}
liked := ap.OrderedCollectionNew(ap.IRI(link))
liked.TotalItems = uint(count)
for _, repo := range repos {
repo := forgefed.RepositoryNew(ap.IRI(strings.TrimSuffix(setting.AppURL, "/") + "/api/v1/activitypub/user/" + repo.OwnerName + "/" + repo.Name))
liked.OrderedItems.Append(repo)
}
response(ctx, liked)
}

View file

@ -0,0 +1,198 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package activitypub
import (
"io"
"net/http"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/forgefed"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/api/v1/utils"
ap "github.com/go-ap/activitypub"
)
// Repo function
func Repo(ctx *context.APIContext) {
// swagger:operation GET /activitypub/user/{username}/{reponame} activitypub activitypubRepo
// ---
// summary: Returns the repository
// produces:
// - application/activity+json
// parameters:
// - name: username
// in: path
// description: username of the user
// type: string
// required: true
// - name: reponame
// in: path
// description: name of the repository
// type: string
// required: true
// responses:
// "200":
// "$ref": "#/responses/ActivityPub"
link := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(ctx.Req.URL.EscapedPath(), "/")
repo := forgefed.RepositoryNew(ap.IRI(link))
repo.Name = ap.NaturalLanguageValuesNew()
err := repo.Name.Set("en", ap.Content(ctx.Repo.Repository.Name))
if err != nil {
ctx.Error(http.StatusInternalServerError, "Set Name", err)
return
}
repo.AttributedTo = ap.IRI(strings.TrimSuffix(link, "/"+ctx.Repo.Repository.Name))
repo.Summary = ap.NaturalLanguageValuesNew()
err = repo.Summary.Set("en", ap.Content(ctx.Repo.Repository.Description))
if err != nil {
ctx.Error(http.StatusInternalServerError, "Set Description", err)
return
}
repo.Inbox = ap.IRI(link + "/inbox")
repo.Outbox = ap.IRI(link + "/outbox")
repo.Followers = ap.IRI(link + "/followers")
repo.Team = ap.IRI(link + "/team")
response(ctx, repo)
}
// RepoInbox function
func RepoInbox(ctx *context.APIContext) {
// swagger:operation POST /activitypub/user/{username}/{reponame}/inbox activitypub activitypubRepoInbox
// ---
// summary: Send to the inbox
// produces:
// - application/activity+json
// parameters:
// - name: username
// in: path
// description: username of the user
// type: string
// required: true
// - name: reponame
// in: path
// description: name of the repository
// type: string
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
body, err := io.ReadAll(ctx.Req.Body)
if err != nil {
ctx.Error(http.StatusInternalServerError, "Error reading request body", err)
}
var activity ap.Activity
activity.UnmarshalJSON(body)
if activity.Type == ap.FollowType {
// activitypub.Follow(ctx, activity)
} else {
log.Warn("ActivityStreams type not supported", activity)
}
ctx.Status(http.StatusNoContent)
}
// RepoOutbox function
func RepoOutbox(ctx *context.APIContext) {
// swagger:operation GET /activitypub/user/{username}/outbox activitypub activitypubPersonOutbox
// ---
// summary: Returns the outbox
// produces:
// - application/activity+json
// parameters:
// - name: username
// in: path
// description: username of the user
// type: string
// required: true
// - name: reponame
// in: path
// description: name of the repository
// type: string
// required: true
// responses:
// "200":
// "$ref": "#/responses/ActivityPub"
link := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(ctx.Req.URL.EscapedPath(), "/")
feed, err := models.GetFeeds(ctx, models.GetFeedsOptions{
RequestedUser: ctx.ContextUser,
Actor: ctx.ContextUser,
IncludePrivate: false,
OnlyPerformedBy: true,
IncludeDeleted: false,
Date: ctx.FormString("date"),
})
if err != nil {
ctx.Error(http.StatusInternalServerError, "Couldn't fetch outbox", err)
}
outbox := ap.OrderedCollectionNew(ap.IRI(link))
for _, action := range feed {
/*if action.OpType == ExampleType {
activity := ap.ExampleNew()
outbox.OrderedItems.Append(activity)
}*/
log.Debug(action.Content)
}
outbox.TotalItems = uint(len(outbox.OrderedItems))
response(ctx, outbox)
}
// RepoFollowers function
func RepoFollowers(ctx *context.APIContext) {
// swagger:operation GET /activitypub/user/{username}/{reponame}/followers activitypub activitypubRepoFollowers
// ---
// summary: Returns the followers collection
// produces:
// - application/activity+json
// parameters:
// - name: username
// in: path
// description: username of the user
// type: string
// required: true
// - name: reponame
// in: path
// description: name of the repository
// type: string
// required: true
// responses:
// "200":
// "$ref": "#/responses/ActivityPub"
link := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(ctx.Req.URL.EscapedPath(), "/")
users, err := user_model.GetUserFollowers(ctx.ContextUser, utils.GetListOptions(ctx))
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserFollowers", err)
return
}
followers := ap.OrderedCollectionNew(ap.IRI(link))
followers.TotalItems = uint(len(users))
for _, user := range users {
person := ap.PersonNew(ap.IRI(user.Website))
followers.OrderedItems.Append(person)
}
response(ctx, followers)
}

View file

@ -0,0 +1,82 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package activitypub
import (
"crypto"
"crypto/x509"
"encoding/pem"
"fmt"
"net/http"
"net/url"
"code.gitea.io/gitea/modules/activitypub"
gitea_context "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
ap "github.com/go-ap/activitypub"
"github.com/go-fed/httpsig"
)
func getPublicKeyFromResponse(b []byte, keyID *url.URL) (p crypto.PublicKey, err error) {
person := ap.PersonNew(ap.IRI(keyID.String()))
err = person.UnmarshalJSON(b)
if err != nil {
err = fmt.Errorf("ActivityStreams type cannot be converted to one known to have publicKey property: %v", err)
return
}
pubKey := person.PublicKey
if pubKey.ID.String() != keyID.String() {
err = fmt.Errorf("cannot find publicKey with id: %s in %s", keyID, string(b))
return
}
pubKeyPem := pubKey.PublicKeyPem
block, _ := pem.Decode([]byte(pubKeyPem))
if block == nil || block.Type != "PUBLIC KEY" {
err = fmt.Errorf("could not decode publicKeyPem to PUBLIC KEY pem block type")
return
}
p, err = x509.ParsePKIXPublicKey(block.Bytes)
return
}
func verifyHTTPSignatures(ctx *gitea_context.APIContext) (authenticated bool, err error) {
r := ctx.Req
// 1. Figure out what key we need to verify
v, err := httpsig.NewVerifier(r)
if err != nil {
return
}
ID := v.KeyId()
idIRI, err := url.Parse(ID)
if err != nil {
return
}
// 2. Fetch the public key of the other actor
b, err := activitypub.Fetch(idIRI)
if err != nil {
return
}
pubKey, err := getPublicKeyFromResponse(b, idIRI)
if err != nil {
return
}
// 3. Verify the other actor's key
algo := httpsig.Algorithm(setting.Federation.Algorithms[0])
authenticated = v.Verify(pubKey, algo) == nil
return
}
// ReqHTTPSignature function
func ReqHTTPSignature() func(ctx *gitea_context.APIContext) {
return func(ctx *gitea_context.APIContext) {
if authenticated, err := verifyHTTPSignatures(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "verifyHttpSignatures", err)
} else if !authenticated {
ctx.Error(http.StatusForbidden, "reqSignature", "request signature verification failed")
}
}
}

View file

@ -0,0 +1,29 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package activitypub
import (
"net/http"
"code.gitea.io/gitea/modules/activitypub"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
ap "github.com/go-ap/activitypub"
"github.com/go-ap/jsonld"
)
func response(ctx *context.APIContext, v interface{}) {
binary, err := jsonld.WithContext(jsonld.IRI(ap.ActivityBaseURI), jsonld.IRI(ap.SecurityContextURI)).Marshal(v)
if err != nil {
ctx.Error(http.StatusInternalServerError, "Marshal", err)
return
}
ctx.Resp.Header().Add("Content-Type", activitypub.ActivityStreamsContentType)
ctx.Resp.WriteHeader(http.StatusOK)
if _, err = ctx.Resp.Write(binary); err != nil {
log.Error("write to resp err: %v", err)
}
}

View file

@ -81,6 +81,7 @@ import (
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/activitypub"
"code.gitea.io/gitea/routers/api/v1/admin"
"code.gitea.io/gitea/routers/api/v1/misc"
"code.gitea.io/gitea/routers/api/v1/notify"
@ -643,6 +644,22 @@ func Routes() *web.Route {
m.Get("/version", misc.Version)
if setting.Federation.Enabled {
m.Get("/nodeinfo", misc.NodeInfo)
m.Group("/activitypub", func() {
m.Group("/user/{username}", func() {
m.Get("", activitypub.Person)
m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
m.Get("/outbox", activitypub.PersonOutbox)
m.Get("/following", activitypub.PersonFollowing)
m.Get("/followers", activitypub.PersonFollowers)
m.Get("/liked", activitypub.PersonLiked)
m.Group("/{reponame}", func() {
m.Get("", activitypub.Repo)
m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.RepoInbox)
m.Get("/outbox", activitypub.RepoOutbox)
m.Get("/followers", activitypub.RepoFollowers)
}, repoAssignment())
}, context_service.UserAssignmentAPI())
})
}
m.Get("/signing-key.gpg", misc.SigningKey)
m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown)

View file

@ -0,0 +1,16 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package swagger
import (
api "code.gitea.io/gitea/modules/structs"
)
// ActivityPub
// swagger:response ActivityPub
type swaggerResponseActivityPub struct {
// in:body
Body api.ActivityPub `json:"body"`
}

View file

@ -36,6 +36,12 @@ func Profile(ctx *context.Context) {
return
}
if strings.Contains(ctx.ContextUser.Name, "@") {
ctx.Resp.Header().Add("Location", ctx.ContextUser.Website)
ctx.Resp.WriteHeader(http.StatusTemporaryRedirect)
return
}
if ctx.ContextUser.IsOrganization() {
org.Home(ctx)
return

View file

@ -29,6 +29,7 @@ type webfingerLink struct {
Rel string `json:"rel,omitempty"`
Type string `json:"type,omitempty"`
Href string `json:"href,omitempty"`
Template string `json:"template,omitempty"`
Titles map[string]string `json:"titles,omitempty"`
Properties map[string]interface{} `json:"properties,omitempty"`
}
@ -86,6 +87,7 @@ func WebfingerQuery(ctx *context.Context) {
aliases := []string{
u.HTMLURL(),
appURL.String() + "api/v1/activitypub/user/" + url.PathEscape(u.Name),
}
if !u.KeepEmailPrivate {
aliases = append(aliases, fmt.Sprintf("mailto:%s", u.Email))
@ -101,8 +103,18 @@ func WebfingerQuery(ctx *context.Context) {
Rel: "http://webfinger.net/rel/avatar",
Href: u.AvatarLink(),
},
{
Rel: "self",
Type: "application/activity+json",
Href: appURL.String() + "api/v1/activitypub/user/" + url.PathEscape(u.Name),
},
{
Rel: "http://ostatus.org/schema/1.0/subscribe",
Template: appURL.String() + "api/v1/authorize_interaction?uri={uri}",
},
}
ctx.Resp.Header().Add("Access-Control-Allow-Origin", "*")
ctx.JSON(http.StatusOK, &webfingerJRD{
Subject: fmt.Sprintf("acct:%s@%s", url.QueryEscape(u.Name), appURL.Host),
Aliases: aliases,

View file

@ -23,6 +23,242 @@
},
"basePath": "{{AppSubUrl | JSEscape | Safe}}/api/v1",
"paths": {
"/activitypub/user/{username}": {
"get": {
"produces": [
"application/activity+json"
],
"tags": [
"activitypub"
],
"summary": "Returns the Person actor for a user",
"operationId": "activitypubPerson",
"parameters": [
{
"type": "string",
"description": "username of the user",
"name": "username",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/ActivityPub"
}
}
}
},
"/activitypub/user/{username}/followers": {
"get": {
"produces": [
"application/activity+json"
],
"tags": [
"activitypub"
],
"summary": "Returns the Liked Collection",
"operationId": "activitypubPersonLiked",
"parameters": [
{
"type": "string",
"description": "username of the user",
"name": "username",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/ActivityPub"
}
}
}
},
"/activitypub/user/{username}/following": {
"get": {
"produces": [
"application/activity+json"
],
"tags": [
"activitypub"
],
"summary": "Returns the Following Collection",
"operationId": "activitypubPersonFollowing",
"parameters": [
{
"type": "string",
"description": "username of the user",
"name": "username",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/ActivityPub"
}
}
}
},
"/activitypub/user/{username}/inbox": {
"post": {
"produces": [
"application/activity+json"
],
"tags": [
"activitypub"
],
"summary": "Send to the inbox",
"operationId": "activitypubPersonInbox",
"parameters": [
{
"type": "string",
"description": "username of the user",
"name": "username",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"$ref": "#/responses/empty"
}
}
}
},
"/activitypub/user/{username}/outbox": {
"get": {
"produces": [
"application/activity+json"
],
"tags": [
"activitypub"
],
"summary": "Returns the outbox",
"operationId": "activitypubPersonOutbox",
"parameters": [
{
"type": "string",
"description": "username of the user",
"name": "username",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repository",
"name": "reponame",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/ActivityPub"
}
}
}
},
"/activitypub/user/{username}/{reponame}": {
"get": {
"produces": [
"application/activity+json"
],
"tags": [
"activitypub"
],
"summary": "Returns the repository",
"operationId": "activitypubRepo",
"parameters": [
{
"type": "string",
"description": "username of the user",
"name": "username",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repository",
"name": "reponame",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/ActivityPub"
}
}
}
},
"/activitypub/user/{username}/{reponame}/followers": {
"get": {
"produces": [
"application/activity+json"
],
"tags": [
"activitypub"
],
"summary": "Returns the followers collection",
"operationId": "activitypubRepoFollowers",
"parameters": [
{
"type": "string",
"description": "username of the user",
"name": "username",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repository",
"name": "reponame",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/ActivityPub"
}
}
}
},
"/activitypub/user/{username}/{reponame}/inbox": {
"post": {
"produces": [
"application/activity+json"
],
"tags": [
"activitypub"
],
"summary": "Send to the inbox",
"operationId": "activitypubRepoInbox",
"parameters": [
{
"type": "string",
"description": "username of the user",
"name": "username",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repository",
"name": "reponame",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"$ref": "#/responses/empty"
}
}
}
},
"/admin/cron": {
"get": {
"produces": [
@ -13113,6 +13349,17 @@
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"ActivityPub": {
"description": "ActivityPub type",
"type": "object",
"properties": {
"@context": {
"type": "string",
"x-go-name": "Context"
}
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"AddCollaboratorOption": {
"description": "AddCollaboratorOption options when adding a user as a collaborator of a repository",
"type": "object",
@ -18794,6 +19041,12 @@
}
}
},
"ActivityPub": {
"description": "ActivityPub",
"schema": {
"$ref": "#/definitions/ActivityPub"
}
},
"AnnotatedTag": {
"description": "AnnotatedTag",
"schema": {

View file

@ -1,3 +1 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="448" height="448" viewBox="0 0 448 448">
<path d="M271.5 0v384l-68 32c-115-10.25-203.5-71.5-203.5-145.75 0-71.5 82.5-131 191.75-144.25v43c-71.5 12.5-124 53-124 101.25 0 51 58.5 93.25 135.75 103v0-340zM438.75 145.5l9.25 97.5-131.25-28.5 36.75-20.75c-19.5-11.5-43.5-20-70-24.75v-43c46.25 5.5 87.75 19.5 120.25 39.25z"></path>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="448" height="448" version="1.1" viewBox="0 0 448 448"><path d="M271.5 0v384l-68 32c-115-10.25-203.5-71.5-203.5-145.75 0-71.5 82.5-131 191.75-144.25v43c-71.5 12.5-124 53-124 101.25 0 51 58.5 93.25 135.75 103v0-340zM438.75 145.5l9.25 97.5-131.25-28.5 36.75-20.75c-19.5-11.5-43.5-20-70-24.75v-43c46.25 5.5 87.75 19.5 120.25 39.25z"/></svg>

Before

Width:  |  Height:  |  Size: 393 B

After

Width:  |  Height:  |  Size: 383 B

View file

@ -1,3 +1 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="416" height="448" viewBox="0 0 416 448">
<path d="M170.5 251.5v162.75l-170.5-23.5v-139.25h170.5zM170.5 65.75v164.75h-170.5v-141.25zM416 251.5v196.5l-226.75-31.25v-165.25h226.75zM416 32v198.5h-226.75v-167.25z"></path>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448" version="1.1" viewBox="0 0 416 448"><path d="M170.5 251.5v162.75l-170.5-23.5v-139.25h170.5zM170.5 65.75v164.75h-170.5v-141.25zM416 251.5v196.5l-226.75-31.25v-165.25h226.75zM416 32v198.5h-226.75v-167.25z"/></svg>

Before

Width:  |  Height:  |  Size: 286 B

After

Width:  |  Height:  |  Size: 276 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="64px" height="64px"><path d="M42.2,22.1L25.9,5.8C25.4,5.3,24.7,5,24,5c0,0,0,0,0,0c-0.7,0-1.4,0.3-1.9,0.8l-3.5,3.5l4.1,4.1c0.4-0.2,0.8-0.3,1.3-0.3c1.7,0,3,1.3,3,3c0,0.5-0.1,0.9-0.3,1.3l4,4c0.4-0.2,0.8-0.3,1.3-0.3c1.7,0,3,1.3,3,3s-1.3,3-3,3c-1.7,0-3-1.3-3-3c0-0.5,0.1-0.9,0.3-1.3l-4-4c-0.1,0-0.2,0.1-0.3,0.1v10.4c1.2,0.4,2,1.5,2,2.8c0,1.7-1.3,3-3,3s-3-1.3-3-3c0-1.3,0.8-2.4,2-2.8V18.8c-1.2-0.4-2-1.5-2-2.8c0-0.5,0.1-0.9,0.3-1.3l-4.1-4.1L5.8,22.1C5.3,22.6,5,23.3,5,24c0,0.7,0.3,1.4,0.8,1.9l16.3,16.3c0,0,0,0,0,0c0.5,0.5,1.2,0.8,1.9,0.8s1.4-0.3,1.9-0.8l16.3-16.3c0.5-0.5,0.8-1.2,0.8-1.9C43,23.3,42.7,22.6,42.2,22.1z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 48 48"><path d="M42.2,22.1L25.9,5.8C25.4,5.3,24.7,5,24,5c0,0,0,0,0,0c-0.7,0-1.4,0.3-1.9,0.8l-3.5,3.5l4.1,4.1c0.4-0.2,0.8-0.3,1.3-0.3c1.7,0,3,1.3,3,3c0,0.5-0.1,0.9-0.3,1.3l4,4c0.4-0.2,0.8-0.3,1.3-0.3c1.7,0,3,1.3,3,3s-1.3,3-3,3c-1.7,0-3-1.3-3-3c0-0.5,0.1-0.9,0.3-1.3l-4-4c-0.1,0-0.2,0.1-0.3,0.1v10.4c1.2,0.4,2,1.5,2,2.8c0,1.7-1.3,3-3,3s-3-1.3-3-3c0-1.3,0.8-2.4,2-2.8V18.8c-1.2-0.4-2-1.5-2-2.8c0-0.5,0.1-0.9,0.3-1.3l-4.1-4.1L5.8,22.1C5.3,22.6,5,23.3,5,24c0,0.7,0.3,1.4,0.8,1.9l16.3,16.3c0,0,0,0,0,0c0.5,0.5,1.2,0.8,1.9,0.8s1.4-0.3,1.9-0.8l16.3-16.3c0.5-0.5,0.8-1.2,0.8-1.9C43,23.3,42.7,22.6,42.2,22.1z"/></svg>

Before

Width:  |  Height:  |  Size: 687 B

After

Width:  |  Height:  |  Size: 683 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64px" height="64px"><linearGradient id="KpzH_ttTMIjq8dhx1zD2pa" x1="30.999" x2="30.999" y1="16" y2="55.342" gradientUnits="userSpaceOnUse" spreadMethod="reflect"><stop offset="0" stop-color="#6dc7ff"/><stop offset="1" stop-color="#e6abff"/></linearGradient><path fill="url(#KpzH_ttTMIjq8dhx1zD2pa)" d="M25.008,56.007c-0.003-0.368-0.006-1.962-0.009-3.454l-0.003-1.55 c-6.729,0.915-8.358-3.78-8.376-3.83c-0.934-2.368-2.211-3.045-2.266-3.073l-0.124-0.072c-0.463-0.316-1.691-1.157-1.342-2.263 c0.315-0.997,1.536-1.1,2.091-1.082c3.074,0.215,4.63,2.978,4.694,3.095c1.569,2.689,3.964,2.411,5.509,1.844 c0.144-0.688,0.367-1.32,0.659-1.878C20.885,42.865,15.27,40.229,15.27,30.64c0-2.633,0.82-4.96,2.441-6.929 c-0.362-1.206-0.774-3.666,0.446-6.765l0.174-0.442l0.452-0.144c0.416-0.137,2.688-0.624,7.359,2.433 c1.928-0.494,3.969-0.749,6.074-0.759c2.115,0.01,4.158,0.265,6.09,0.759c4.667-3.058,6.934-2.565,7.351-2.433l0.451,0.145 l0.174,0.44c1.225,3.098,0.813,5.559,0.451,6.766c1.618,1.963,2.438,4.291,2.438,6.929c0,9.591-5.621,12.219-10.588,13.087 c0.563,1.065,0.868,2.402,0.868,3.878c0,1.683-0.007,7.204-0.015,8.402l-2-0.014c0.008-1.196,0.015-6.708,0.015-8.389 c0-2.442-0.943-3.522-1.35-3.874l-1.73-1.497l2.274-0.253c5.205-0.578,10.525-2.379,10.525-11.341c0-2.33-0.777-4.361-2.31-6.036 l-0.43-0.469l0.242-0.587c0.166-0.401,0.894-2.442-0.043-5.291c-0.758,0.045-2.568,0.402-5.584,2.447l-0.384,0.259l-0.445-0.123 c-1.863-0.518-3.938-0.796-6.001-0.806c-2.052,0.01-4.124,0.288-5.984,0.806l-0.445,0.123l-0.383-0.259 c-3.019-2.044-4.833-2.404-5.594-2.449c-0.935,2.851-0.206,4.892-0.04,5.293l0.242,0.587l-0.429,0.469 c-1.536,1.681-2.314,3.712-2.314,6.036c0,8.958,5.31,10.77,10.504,11.361l2.252,0.256l-1.708,1.49 c-0.372,0.325-1.03,1.112-1.254,2.727l-0.075,0.549l-0.506,0.227c-1.321,0.592-5.839,2.162-8.548-2.485 c-0.015-0.025-0.544-0.945-1.502-1.557c0.646,0.639,1.433,1.673,2.068,3.287c0.066,0.19,1.357,3.622,7.28,2.339l1.206-0.262 l0.012,3.978c0.003,1.487,0.006,3.076,0.009,3.444L25.008,56.007z"/><linearGradient id="KpzH_ttTMIjq8dhx1zD2pb" x1="32" x2="32" y1="5" y2="59.167" gradientUnits="userSpaceOnUse" spreadMethod="reflect"><stop offset="0" stop-color="#1a6dff"/><stop offset="1" stop-color="#c822ff"/></linearGradient><path fill="url(#KpzH_ttTMIjq8dhx1zD2pb)" d="M32,58C17.663,58,6,46.337,6,32S17.663,6,32,6s26,11.663,26,26S46.337,58,32,58z M32,8 C18.767,8,8,18.767,8,32s10.767,24,24,24s24-10.767,24-24S45.233,8,32,8z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><linearGradient id="KpzH_ttTMIjq8dhx1zD2pa" x1="30.999" x2="30.999" y1="16" y2="55.342" gradientUnits="userSpaceOnUse" spreadMethod="reflect"><stop offset="0" stop-color="#6dc7ff"/><stop offset="1" stop-color="#e6abff"/></linearGradient><path fill="url(#KpzH_ttTMIjq8dhx1zD2pa)" d="M25.008,56.007c-0.003-0.368-0.006-1.962-0.009-3.454l-0.003-1.55 c-6.729,0.915-8.358-3.78-8.376-3.83c-0.934-2.368-2.211-3.045-2.266-3.073l-0.124-0.072c-0.463-0.316-1.691-1.157-1.342-2.263 c0.315-0.997,1.536-1.1,2.091-1.082c3.074,0.215,4.63,2.978,4.694,3.095c1.569,2.689,3.964,2.411,5.509,1.844 c0.144-0.688,0.367-1.32,0.659-1.878C20.885,42.865,15.27,40.229,15.27,30.64c0-2.633,0.82-4.96,2.441-6.929 c-0.362-1.206-0.774-3.666,0.446-6.765l0.174-0.442l0.452-0.144c0.416-0.137,2.688-0.624,7.359,2.433 c1.928-0.494,3.969-0.749,6.074-0.759c2.115,0.01,4.158,0.265,6.09,0.759c4.667-3.058,6.934-2.565,7.351-2.433l0.451,0.145 l0.174,0.44c1.225,3.098,0.813,5.559,0.451,6.766c1.618,1.963,2.438,4.291,2.438,6.929c0,9.591-5.621,12.219-10.588,13.087 c0.563,1.065,0.868,2.402,0.868,3.878c0,1.683-0.007,7.204-0.015,8.402l-2-0.014c0.008-1.196,0.015-6.708,0.015-8.389 c0-2.442-0.943-3.522-1.35-3.874l-1.73-1.497l2.274-0.253c5.205-0.578,10.525-2.379,10.525-11.341c0-2.33-0.777-4.361-2.31-6.036 l-0.43-0.469l0.242-0.587c0.166-0.401,0.894-2.442-0.043-5.291c-0.758,0.045-2.568,0.402-5.584,2.447l-0.384,0.259l-0.445-0.123 c-1.863-0.518-3.938-0.796-6.001-0.806c-2.052,0.01-4.124,0.288-5.984,0.806l-0.445,0.123l-0.383-0.259 c-3.019-2.044-4.833-2.404-5.594-2.449c-0.935,2.851-0.206,4.892-0.04,5.293l0.242,0.587l-0.429,0.469 c-1.536,1.681-2.314,3.712-2.314,6.036c0,8.958,5.31,10.77,10.504,11.361l2.252,0.256l-1.708,1.49 c-0.372,0.325-1.03,1.112-1.254,2.727l-0.075,0.549l-0.506,0.227c-1.321,0.592-5.839,2.162-8.548-2.485 c-0.015-0.025-0.544-0.945-1.502-1.557c0.646,0.639,1.433,1.673,2.068,3.287c0.066,0.19,1.357,3.622,7.28,2.339l1.206-0.262 l0.012,3.978c0.003,1.487,0.006,3.076,0.009,3.444L25.008,56.007z"/><linearGradient id="KpzH_ttTMIjq8dhx1zD2pb" x1="32" x2="32" y1="5" y2="59.167" gradientUnits="userSpaceOnUse" spreadMethod="reflect"><stop offset="0" stop-color="#1a6dff"/><stop offset="1" stop-color="#c822ff"/></linearGradient><path fill="url(#KpzH_ttTMIjq8dhx1zD2pb)" d="M32,58C17.663,58,6,46.337,6,32S17.663,6,32,6s26,11.663,26,26S46.337,58,32,58z M32,8 C18.767,8,8,18.767,8,32s10.767,24,24,24s24-10.767,24-24S45.233,8,32,8z"/></svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="64px" height="64px"><path fill="#e53935" d="M24 43L16 20 32 20z"/><path fill="#ff7043" d="M24 43L42 20 32 20z"/><path fill="#e53935" d="M37 5L42 20 32 20z"/><path fill="#ffa726" d="M24 43L42 20 45 28z"/><path fill="#ff7043" d="M24 43L6 20 16 20z"/><path fill="#e53935" d="M11 5L6 20 16 20z"/><path fill="#ffa726" d="M24 43L6 20 3 28z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 48 48"><path fill="#e53935" d="M24 43L16 20 32 20z"/><path fill="#ff7043" d="M24 43L42 20 32 20z"/><path fill="#e53935" d="M37 5L42 20 32 20z"/><path fill="#ffa726" d="M24 43L42 20 45 28z"/><path fill="#ff7043" d="M24 43L6 20 16 20z"/><path fill="#e53935" d="M11 5L6 20 16 20z"/><path fill="#ffa726" d="M24 43L6 20 3 28z"/></svg>

Before

Width:  |  Height:  |  Size: 409 B

After

Width:  |  Height:  |  Size: 405 B

View file

@ -1,60 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="67.73333mm"
height="67.73333mm"
viewBox="0 0 67.73333 67.73333"
version="1.1"
id="svg8"
inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
sodipodi:docname="gitea-gogs.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.4352161"
inkscape:cx="145.15203"
inkscape:cy="129.56614"
inkscape:document-units="mm"
inkscape:current-layer="layer3"
inkscape:document-rotation="0"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1006"
inkscape:window-x="1200"
inkscape:window-y="444"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Layer 3"
style="display:inline">
<path
style="display:inline;fill:#d75547;fill-opacity:1;fill-rule:evenodd;stroke:#428f29;stroke-width:0.0190672;paint-order:markers fill stroke"
d="M 28.763808,62.186078 C 28.552224,62.156588 28.3282,62.079645 28.265977,62.01509 28.123377,61.867145 27.941284,61.235718 27.375971,58.928893 27.128273,57.918138 26.870167,56.952588 26.8024,56.783223 26.653428,56.410912 26.321729,56.197407 24.664484,55.407125 22.815394,54.525354 20.800132,53.303558 19.034519,51.99383 l -0.753641,-0.55905 -2.322335,0.678345 c -1.277286,0.37309 -2.657942,0.75099 -3.068125,0.839774 l -0.745787,0.161424 -0.351437,-0.536616 C 10.841488,51.124528 8.2297585,46.620395 7.1670955,44.599636 L 6.6102577,43.540752 7.0934858,42.948695 c 0.2657754,-0.325634 1.2926661,-1.41771 2.2819797,-2.426837 l 1.7987515,-1.834779 -0.180416,-1.038637 c -0.160803,-0.925735 -0.180684,-1.319661 -0.182886,-3.623976 -0.002,-2.082515 0.02593,-2.77882 0.143552,-3.580102 L 11.100491,29.449609 9.0366642,27.414662 C 7.5050421,25.904473 6.9326263,25.287565 6.8169034,25.02237 6.6626002,24.668764 6.6626297,24.660735 6.8197249,24.254845 7.2963868,23.023252 11.239804,16.273894 12.005659,15.378857 l 0.257067,-0.300427 0.484759,0.125942 c 0.266618,0.06927 1.585016,0.43706 2.929773,0.817315 l 2.445013,0.691373 0.429771,-0.260466 c 0.236371,-0.143253 0.844892,-0.564341 1.352266,-0.935741 1.30433,-0.954784 2.690014,-1.762213 4.707543,-2.74306 1.87475,-0.911433 1.838916,-0.883043 2.124645,-1.683256 0.06563,-0.1838 0.336217,-1.1703787 0.601305,-2.1923981 0.26509,-1.0220196 0.573575,-2.1360624 0.685518,-2.4756513 0.17614,-0.5343091 0.23295,-0.623873 0.421984,-0.6652627 0.483669,-0.1058996 3.97054,-0.1502609 7.292057,-0.092772 l 3.518704,0.060902 0.430989,1.7479767 c 0.510047,2.0686117 0.909017,3.4804444 1.127722,3.9906574 0.174557,0.407221 0.0081,0.308631 2.593742,1.53554 1.3556,0.643225 2.654323,1.424602 4.307061,2.591347 0.702523,0.495943 1.33877,0.943783 1.413882,0.995202 0.109699,0.0751 0.502152,-0.01615 1.994813,-0.463793 1.022033,-0.306501 2.381778,-0.689488 3.021651,-0.85108 l 1.163411,-0.293805 0.145052,0.19205 c 0.93221,1.234241 5.324678,8.900157 5.324678,9.292846 0,0.333447 -0.488016,0.914807 -2.540796,3.02678 l -1.893181,1.947777 0.15824,0.960735 c 0.227755,1.382822 0.274355,3.126299 0.15827,5.921847 l -0.101763,2.450639 1.510118,1.495377 c 1.549811,1.534681 2.47101,2.550338 2.683271,2.958414 0.115947,0.22291 0.103768,0.264805 -0.328833,1.13109 -1.289906,2.583039 -4.510781,8.106197 -4.924647,8.444791 -0.229142,0.187467 -0.906252,0.05936 -3.361841,-0.636096 -1.264388,-0.358089 -2.427812,-0.66997 -2.585382,-0.693076 -0.254259,-0.03729 -0.377393,0.02128 -1.094426,0.520539 -2.75021,1.914888 -3.396183,2.301016 -5.615132,3.356412 -0.864328,0.4111 -1.586938,0.808234 -1.713456,0.94169 -0.279925,0.295269 -0.499881,1.010417 -1.141053,3.709893 l -0.508517,2.140988 -1.893589,0.04981 c -2.516342,0.0662 -8.338233,0.06367 -8.822539,-0.0038 z m 7.858077,-12.120535 c 2.091378,-0.388455 5.175143,-1.723813 6.867427,-2.973786 1.796481,-1.326945 4.757949,-4.883235 4.97652,-5.976082 0.04707,-0.23538 0.0195,-0.268126 -0.544626,-0.646577 -0.89966,-0.603557 -2.187787,-1.377201 -5.078243,-3.049968 -4.184205,-2.421491 -4.52345,-2.676285 -4.524118,-3.397889 -0.0011,-1.340016 -1.219035,-3.278179 -2.4241,-3.858035 -1.790528,-0.861573 -3.841611,-0.52172 -5.213619,0.863866 -0.315085,0.318202 -0.680808,0.789483 -0.82133,1.058382 -1.355657,2.59418 0.09164,5.558218 3.005202,6.154597 0.886416,0.181439 1.72976,0.07365 2.913276,-0.372328 l 0.879991,-0.331607 2.02184,1.158352 c 2.672299,1.531012 3.61875,2.12207 4.1007,2.560884 0.340094,0.309652 0.391458,0.394601 0.346398,0.57285 -0.0768,0.303803 -0.673843,1.002125 -1.394132,1.630629 -1.608465,1.403495 -3.352982,2.265892 -5.547142,2.742214 -1.178042,0.255735 -3.523379,0.256058 -4.699639,6.79e-4 -1.211182,-0.262989 -1.987409,-0.533958 -3.06492,-1.06991 -3.757271,-1.868855 -6.310115,-5.470633 -6.829909,-9.636234 -0.156607,-1.255046 -0.06748,-3.197221 0.200967,-4.379595 1.024517,-4.512371 4.409288,-7.971423 8.971948,-9.168835 1.368354,-0.359109 1.98948,-0.43042 3.32699,-0.381966 1.261093,0.04568 1.953923,0.167871 3.540434,0.624377 0.565292,0.162659 1.094549,0.260446 1.454278,0.268701 0.495297,0.01136 0.620752,-0.01798 1.009916,-0.236201 1.079693,-0.605431 1.3594,-1.855128 0.602683,-2.692712 -1.317562,-1.458359 -6.682213,-2.214558 -10.373764,-1.462279 -2.483279,0.506053 -5.053495,1.805105 -6.993517,3.534699 -2.575021,2.295712 -4.259712,4.711906 -5.127071,7.353271 -0.924677,2.815913 -1.025226,6.141317 -0.275431,9.109059 0.774038,3.063694 2.549965,5.963534 4.958139,8.095943 2.441521,2.161939 5.76675,3.672334 8.927653,4.055148 1.089179,0.13191 3.734827,0.04956 4.807199,-0.149613 z"
id="path851" />
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" id="svg8" width="256" height="256" version="1.1" viewBox="0 0 67.733 67.733"><metadata id="metadata5"/><g id="layer3" style="display:inline"><path style="display:inline;fill:#d75547;fill-opacity:1;fill-rule:evenodd;stroke:#428f29;stroke-width:.0190672;paint-order:markers fill stroke" id="path851" d="M 28.763808,62.186078 C 28.552224,62.156588 28.3282,62.079645 28.265977,62.01509 28.123377,61.867145 27.941284,61.235718 27.375971,58.928893 27.128273,57.918138 26.870167,56.952588 26.8024,56.783223 26.653428,56.410912 26.321729,56.197407 24.664484,55.407125 22.815394,54.525354 20.800132,53.303558 19.034519,51.99383 l -0.753641,-0.55905 -2.322335,0.678345 c -1.277286,0.37309 -2.657942,0.75099 -3.068125,0.839774 l -0.745787,0.161424 -0.351437,-0.536616 C 10.841488,51.124528 8.2297585,46.620395 7.1670955,44.599636 L 6.6102577,43.540752 7.0934858,42.948695 c 0.2657754,-0.325634 1.2926661,-1.41771 2.2819797,-2.426837 l 1.7987515,-1.834779 -0.180416,-1.038637 c -0.160803,-0.925735 -0.180684,-1.319661 -0.182886,-3.623976 -0.002,-2.082515 0.02593,-2.77882 0.143552,-3.580102 L 11.100491,29.449609 9.0366642,27.414662 C 7.5050421,25.904473 6.9326263,25.287565 6.8169034,25.02237 6.6626002,24.668764 6.6626297,24.660735 6.8197249,24.254845 7.2963868,23.023252 11.239804,16.273894 12.005659,15.378857 l 0.257067,-0.300427 0.484759,0.125942 c 0.266618,0.06927 1.585016,0.43706 2.929773,0.817315 l 2.445013,0.691373 0.429771,-0.260466 c 0.236371,-0.143253 0.844892,-0.564341 1.352266,-0.935741 1.30433,-0.954784 2.690014,-1.762213 4.707543,-2.74306 1.87475,-0.911433 1.838916,-0.883043 2.124645,-1.683256 0.06563,-0.1838 0.336217,-1.1703787 0.601305,-2.1923981 0.26509,-1.0220196 0.573575,-2.1360624 0.685518,-2.4756513 0.17614,-0.5343091 0.23295,-0.623873 0.421984,-0.6652627 0.483669,-0.1058996 3.97054,-0.1502609 7.292057,-0.092772 l 3.518704,0.060902 0.430989,1.7479767 c 0.510047,2.0686117 0.909017,3.4804444 1.127722,3.9906574 0.174557,0.407221 0.0081,0.308631 2.593742,1.53554 1.3556,0.643225 2.654323,1.424602 4.307061,2.591347 0.702523,0.495943 1.33877,0.943783 1.413882,0.995202 0.109699,0.0751 0.502152,-0.01615 1.994813,-0.463793 1.022033,-0.306501 2.381778,-0.689488 3.021651,-0.85108 l 1.163411,-0.293805 0.145052,0.19205 c 0.93221,1.234241 5.324678,8.900157 5.324678,9.292846 0,0.333447 -0.488016,0.914807 -2.540796,3.02678 l -1.893181,1.947777 0.15824,0.960735 c 0.227755,1.382822 0.274355,3.126299 0.15827,5.921847 l -0.101763,2.450639 1.510118,1.495377 c 1.549811,1.534681 2.47101,2.550338 2.683271,2.958414 0.115947,0.22291 0.103768,0.264805 -0.328833,1.13109 -1.289906,2.583039 -4.510781,8.106197 -4.924647,8.444791 -0.229142,0.187467 -0.906252,0.05936 -3.361841,-0.636096 -1.264388,-0.358089 -2.427812,-0.66997 -2.585382,-0.693076 -0.254259,-0.03729 -0.377393,0.02128 -1.094426,0.520539 -2.75021,1.914888 -3.396183,2.301016 -5.615132,3.356412 -0.864328,0.4111 -1.586938,0.808234 -1.713456,0.94169 -0.279925,0.295269 -0.499881,1.010417 -1.141053,3.709893 l -0.508517,2.140988 -1.893589,0.04981 c -2.516342,0.0662 -8.338233,0.06367 -8.822539,-0.0038 z m 7.858077,-12.120535 c 2.091378,-0.388455 5.175143,-1.723813 6.867427,-2.973786 1.796481,-1.326945 4.757949,-4.883235 4.97652,-5.976082 0.04707,-0.23538 0.0195,-0.268126 -0.544626,-0.646577 -0.89966,-0.603557 -2.187787,-1.377201 -5.078243,-3.049968 -4.184205,-2.421491 -4.52345,-2.676285 -4.524118,-3.397889 -0.0011,-1.340016 -1.219035,-3.278179 -2.4241,-3.858035 -1.790528,-0.861573 -3.841611,-0.52172 -5.213619,0.863866 -0.315085,0.318202 -0.680808,0.789483 -0.82133,1.058382 -1.355657,2.59418 0.09164,5.558218 3.005202,6.154597 0.886416,0.181439 1.72976,0.07365 2.913276,-0.372328 l 0.879991,-0.331607 2.02184,1.158352 c 2.672299,1.531012 3.61875,2.12207 4.1007,2.560884 0.340094,0.309652 0.391458,0.394601 0.346398,0.57285 -0.0768,0.303803 -0.673843,1.002125 -1.394132,1.630629 -1.608465,1.403495 -3.352982,2.265892 -5.547142,2.742214 -1.178042,0.255735 -3.523379,0.256058 -4.699639,6.79e-4 -1.211182,-0.262989 -1.987409,-0.533958 -3.06492,-1.06991 -3.757271,-1.868855 -6.310115,-5.470633 -6.829909,-9.636234 -0.156607,-1.255046 -0.06748,-3.197221 0.200967,-4.379595 1.024517,-4.512371 4.409288,-7.971423 8.971948,-9.168835 1.368354,-0.359109 1.98948,-0.43042 3.32699,-0.381966 1.261093,0.04568 1.953923,0.167871 3.540434,0.624377 0.565292,0.162659 1.094549,0.260446 1.454278,0.268701 0.495297,0.01136 0.620752,-0.01798 1.009916,-0.236201 1.079693,-0.605431 1.3594,-1.855128 0.602683,-2.692712 -1.317562,-1.458359 -6.682213,-2.214558 -10.373764,-1.462279 -2.483279,0.506053 -5.053495,1.805105 -6.993517,3.534699 -2.575021,2.295712 -4.259712,4.711906 -5.127071,7.353271 -0.924677,2.815913 -1.025226,6.141317 -0.275431,9.109059 0.774038,3.063694 2.549965,5.963534 4.958139,8.095943 2.441521,2.161939 5.76675,3.672334 8.927653,4.055148 1.089179,0.13191 3.734827,0.04956 4.807199,-0.149613 z"/></g></svg>

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB