Compare commits

..

212 commits

Author SHA1 Message Date
kim
5fd52369c9 [performance] handle emoji refreshes asynchronously when fetched as part of account|status dereferences (#4486)
# Description

Updates our dereferencer emoji handling to work asynchronously when going through the route of account or status dereferencing.

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4485

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4486
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-10-08 14:13:40 +02:00
kim
baf2c54730 [performance] add benchmarks for native Go imaging code, small tweaks to reduce nil and boundary checks, some loop unrolling (#4482)
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4482
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-10-08 11:12:12 +02:00
tobi
b012a81f66 [bugfix] Log a warning when clientIP could not be parsed during rate limiting (#4481)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

Fixes a panic when clientIP cannot be parsed in the rate limiting middleware, and warn logs the derived clientIP and a hint that reverse proxy may be misconfigured.

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4479

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4481
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-10-07 16:02:57 +02:00
tobi
c6044d0142 [bugfix] Fix db error checking for int req: sql: no rows in result set (#4478)
Fixes `sql: no rows in result set` when trying to append approvedByURI to a reply that was sent impolitely and approved impolitely.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4478
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-10-06 13:11:23 +02:00
tobi
03fc6eaf39 [bugfix] Fix nil ptr in DifferentFrom func (#4477)
Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4476

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4477
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-10-06 11:45:40 +02:00
Daniël Franke
5b95636993 [docs] Add db migration tip for slow hardware instances. (#4457)
This PR adds a new section to the documentation to contain workarounds for running
GtS on slow hardware. Right now it only contains a procedure on how to run migrations
on a different database instance in case the original database is too slow to finish
a database migration in a timely manner.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4457
Co-authored-by: Daniël Franke <df@ponc.tech>
Co-committed-by: Daniël Franke <df@ponc.tech>
2025-10-05 14:43:09 +02:00
tobi
259fa1ffac [bugfix] Update interaction policies of freshly dereffed statuses if different from last deref (#4474)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

This pull request adds a check to see whether interaction policy on a refreshed status is different from the interaction policy set on that status before, and updates the status with the new policy if it's changed.

Should fix a pesky issue where folks on v0.19.2 and above still can't interact with statuses they dereferenced before updating.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4474
Reviewed-by: kim <gruf@noreply.codeberg.org>
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-10-05 13:33:16 +02:00
kim
57cb4fe748 [bugfix] status refresh race condition causing double edit notifications (#4470)
# Description

fixes possible race condition of existing status being out-of-date in enrichStatus()

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4470
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-10-03 15:50:57 +02:00
kim
ff950e94bb [chore] update dependencies (#4468)
- github.com/ncruces/go-sqlite3
- codeberg.org/gruf/go-mempool
- codeberg.org/gruf/go-structr (changes related on the above) *
- codeberg.org/gruf/go-mutexes (changes related on the above) *

* this is largely just fiddling around with package internals in structr and mutexes to rely on changes in mempool, which added a new concurrency-safe pool

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4468
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-10-03 15:29:41 +02:00
tobi
e7cd8bb43e [chore] Use bulk updates + fewer loops in status rethreading migration (#4459)
This pull request tries to optimize our status rethreading migration by using bulk updates + avoiding unnecessary writes, and doing the migration in one top-level loop and one stragglers loop, without the extra loop to copy thread_id over.

On my machine it runs at about 2400 rows per second on Postgres, now, and about 9000 rows per second on SQLite.

Tried *many* different ways of doing this, with and without temporary indexes, with different batch and transaction sizes, etc., and this seems to be just about the most performant way of getting stuff done.

With the changes, a few minutes have been shaved off migration time testing on my development machine. *Hopefully* this will translate to more time shaved off when running on a vps with slower read/write speed and less processor power.

SQLite before:

```
real	20m58,446s
user	16m26,635s
sys	5m53,648s
```

SQLite after:

```
real	14m25,435s
user	12m47,449s
sys	2m27,898s
```

Postgres before:

```
real	28m25,307s
user	3m40,005s
sys	4m45,018s
```

Postgres after:

```
real	22m31,999s
user	3m46,674s
sys	4m39,592s
```

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4459
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-10-03 12:28:55 +02:00
Zoë Bijl
bd1c43d55e [bugfix/frontend] restore blockquote “block” margin (#4465)
stripping `<blockquote>` of all the margin looks a bit funky. this only removes the inline margin. in English this generally means that it won’t have horizontal margin but will still have vertical margin.

Closes #4466

![before the change any content after the blockquote is flush against it without space](/attachments/7cc808ee-a999-435d-9235-60651a3d9bca)

![after the changes there is vertical rhythm](/attachments/3240480a-14ee-4739-a497-14237879993c)

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes. (I ran `go test ./...` from the main dir, they passed with one exception related to thumbnail file size, most likely caused by testing on macOS)
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4465
Co-authored-by: Zoë Bijl <code@moiety.me>
Co-committed-by: Zoë Bijl <code@moiety.me>
2025-10-01 19:04:44 +02:00
kim
dfdf06e4ad [chore] update dependencies (#4458)
- codeberg.org/gruf/go-ffmpreg: v0.6.11 -> v0.6.12

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4458
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-25 16:38:19 +02:00
kim
3db2d42247 [chore] ffmpeg webassembly fiddling (#4454)
This disables ffmpeg / ffprobe support on platforms where the wazero compiler is not available. The slowness introduced is hard to pindown for admins (and us!), so it's easier to just return an error message linking to docs on attempted media processing. It still allows the instance to run, just erroring if anything other than a jpeg is attempted to be processed. This should hopefully make it easier for users to notice these issues.

Also further locks down our wazero 'allowFiles' fs and other media code to address: https://codeberg.org/superseriousbusiness/gotosocial/issues/4408

relates to: https://codeberg.org/superseriousbusiness/gotosocial/issues/4427
also relates to issues raised in #gotosocial-help on matrix

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4408

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4454
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-24 15:12:25 +02:00
tobi
121677754c [docs] Update tracing.md with up-to-date way of doing things (#4452)
Updates tracing docs with the latest stufffff

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4446

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4452
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-09-22 15:32:04 +02:00
tobi
602022701b [chore] Update config to remove unnecessary square brackets around ipv6 addresses (#4451)
Tweak example config for `bind-address`, as square brackets around ipv6 addresses was causing issues launching.

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4450

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4451
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-09-22 13:10:30 +02:00
tobi
82216281ce [chore/docs] Fix Prometheus metric names for Gin, include example Grafana dash, update docs (#4443)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

This pull request updates some of our inconsistent metric naming, and adds an example Grafana dashboard using all the most up-to-date metrics names, and updates our docs to describe the latest way of setting up metrics.

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4362
Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4055

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Co-authored-by: kim <grufwub@gmail.com>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4443
Reviewed-by: kim <gruf@noreply.codeberg.org>
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-09-18 16:48:45 +02:00
kim
6607e1c944 [feature] add paging support to rss feed endpoint, and support JSON / atom feed types (#4442)
originally based on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4396

hope this is okay https://codeberg.org/zordsdavini !

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4411
closes https://codeberg.org/superseriousbusiness/gotosocial/issues/3407

Co-authored-by: Arnas Udovic <zordsdavini@gmail.com>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4442
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-18 16:33:23 +02:00
kim
e81bcb5171 [chore] update dependencies (#4441)
- modernc.org/sqlite v1.38.2 -> v1.39.0 (w/ concurrency workaround)
- golang.org/x/net v0.43.0 -> v0.44.0

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4441
Reviewed-by: tobi <kipvandenbos@noreply.codeberg.org>
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-17 14:48:09 +02:00
kim
6801ce299a [chore] remove nollamas middleware for now (after discussions with a security advisor) (#4433)
i'll keep this on a separate branch for now while i experiment with other possible alternatives, but for now both our hacky implementation especially, and more popular ones (like anubis) aren't looking too great on the deterrent front: https://github.com/eternal-flame-AD/pow-buster

Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4433
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-17 14:16:53 +02:00
tobi
247733aef4 [bugfix/frontend] Use correct account domain in move account helper (#4440)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

Just a quick fix to the frontend to use the account domain in the move helper namestring thingy, instead of the host.

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4197

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4440
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-09-17 13:37:28 +02:00
tobi
5533fbc1f8 [bugfix/frontend] Fix overzealous padding removal on caption (#4439)
Leave just a little bit of padding between media + caption, for the lads!

[image](/attachments/5802a3d1-15c6-4ca2-8de2-4a149ba69f54)

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4439
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-09-17 12:15:05 +02:00
tobi
11f39bead0 [feature] Stub out trends + suggestions (always return empty array) (#4435)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

This pull request stubs out the trends and suggestions APIs, just returning empty arrays for all four of the added endpoints. This is to help clients show fewer errors. It does *not* signal any intention to actually implement these endpoints properly, though you never know.

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4385

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4435
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-09-16 14:30:39 +02:00
ptrcnull
0a32fc0980 [bugfix] prevent clicking Enter in description field from deleting the image (#4436)
# Description

Change the type of "Delete header" / "Delete avatar" button to just "button" to prevent them from getting deleted if user presses Enter in the description field.

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4363

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Co-authored-by: ptrcnull <git@ptrcnull.me>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4436
Co-authored-by: ptrcnull <ptrcnull@noreply.codeberg.org>
Co-committed-by: ptrcnull <ptrcnull@noreply.codeberg.org>
2025-09-16 14:30:00 +02:00
tobi
10b8d270f2 [bugfix/frontend] preserve whitespace in photoswipe captions (#4434)
This PR fixes https://codeberg.org/superseriousbusiness/gotosocial/issues/4382 by updating the photoswipe caption plugin CSS to include whitespace. Thanks @olivergeer for the fix. It also updates the padding + width in "aside" mode to increase the chances of a visitor being able to read an entire caption, in lieu of https://codeberg.org/superseriousbusiness/gotosocial/issues/4413 being fixable.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4434
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-09-16 13:00:30 +02:00
kim
882d07db5f [bugfix] API status edit history returned in inverse order (#4432)
Simply reverses the order in which we build status edit history for the frontend. In fact now it matches how we store it in the database which is even easier :p. Why I thought it needed to be returned inverse to begin with? Who knows.

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4426 (thank you [@DarkCat09](https://codeberg.org/DarkCat09) for pointing it out!)

Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4432
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-15 18:28:48 +02:00
Markus Unterwaditzer
d9ee6cddea [docs] Fix broken links and typos (#4418)
# Description

Fix links and typos in docs and settings page:

* Fix https://codeberg.org/superseriousbusiness/gotosocial/issues/4328
* Fix https://codeberg.org/superseriousbusiness/gotosocial/issues/4360

Also fix broken issuetracker links as forgejo does not support search
queries like "label:bug"

The translation for Zh-cn still says "this project" according to google
translate, I only fixed the link.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4418
Co-authored-by: Markus Unterwaditzer <markus-tarpit+git@unterwaditzer.net>
Co-committed-by: Markus Unterwaditzer <markus-tarpit+git@unterwaditzer.net>
2025-09-15 17:31:06 +02:00
tobi
f9cb086c53 [bugfix] Parse scheduled_at as ISO8601 with offset if RFC3339 parse fails (#4431)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4409 by reattempting `scheduled_at` parsing using ISO8601 offset.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4431
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-09-15 13:26:50 +02:00
tobi
754b7be9cf [feature] Support new model of interaction flow for forward compat with v0.21.0 (#4394)
~~Still WIP!~~

This PR allows v0.20.0 of GtS to be forward-compatible with the interaction request / authorization flow that will fully replace the current flow in v0.21.0.

Basically, this means we need to recognize LikeRequest, ReplyRequest, and AnnounceRequest, and in response to those requests, deliver either a Reject or an Accept, with the latter pointing towards a LikeAuthorization, ReplyAuthorization, or AnnounceAuthorization, respectively. This can then be used by the remote instance to prove to third parties that the interaction has been accepted by the interactee. These Authorization types need to be dereferencable to third parties, so we need to serve them.

As well as recognizing the above "polite" interaction request types, we also need to still serve appropriate responses to "impolite" interaction request types, where an instance that's unaware of interaction policies tries to interact with a post by sending a reply, like, or boost directly, without wrapping it in a WhateverRequest type.

Doesn't fully close https://codeberg.org/superseriousbusiness/gotosocial/issues/4026 but gets damn near (just gotta update the federating with GtS documentation).

Migrations tested on both Postgres and SQLite.

Co-authored-by: kim <grufwub@gmail.com>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4394
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-09-14 15:37:35 +02:00
kim
33fed81a8d [bugfix] set link header lo,hi values directly from returned slice, don't account for filtering (#4421)
this fixes an issue with list pagination in list timelines as seen here: https://codeberg.org/tusky/Tusky/issues/5235

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4421
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-11 14:57:32 +02:00
kim
c949b9f2d1 [chore] update dependencies (#4423)
- codeberg.org/gruf/go-ffmpreg: v0.6.10 -> v0.6.11
- github.com/spf13/cast: v1.9.2 -> v1.10.0
- github.com/spf13/viper: v1.20.1 -> v1.21.0
- golang.org/x/crypto: v0.41.0 -> v0.42.0
- golang.org/x/image: v0.30.0 -> v0.31.0

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4423
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-09 16:12:29 +02:00
kim
a6429b5410 [chore] update dependencies (#4422)
- github.com/jackc/pgx/v5 v5.7.5 -> v5.7.6
- github.com/ncruces/go-sqlite3 v0.28.0 -> v0.29.0
- github.com/tdewolff/minify/v2 v2.24.2 -> v2.24.3
- golang.org/x/oauth2 v0.30.0 -> v0.31.0
- golang.org/x/sys v0.35.0 -> v0.36.0
- golang.org/x/text v0.28.0 -> v0.29.0

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4422
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-08 20:53:25 +02:00
kim
9b7db51436 [bugfix] check for nil notification (#4417)
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4417
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-07 18:16:43 +02:00
kim
4b6c65fc15 [bugfix] ensure std log writer passes byte slices along as string, or JSON will encode as base64 raw bytes (#4416)
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4416
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-07 16:16:06 +02:00
kim
19784e381b [performance] more logging tweaks (#4415)
- reduces number of necessary function calls by moving log level checking out of the uninlineable `logf(...)` function and into each of its caller (which are all inlined). this in turn means the log level check is performed in-situ wherever a call to `log.Debug(...)` (etc) is made, reduce unnecessary calls when a certain log level is disabled.
- sets the http.Server{}.ErrorLog to output to our internal logging package (which in turn ensures it gets wrapped in either our logfmt or json log formatting)

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4415
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-07 14:47:45 +02:00
kim
ed3035699f [bugfix] fix lo paging value not always being set (#4407)
the "lo" paging value wasn't always being set when loading statuses from the database. this seems to (potentially) fix an issue in tusky with list timelines showing repeated posts.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4407
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-04 18:06:26 +02:00
kim
78defcd916 [chore] bump dependencies (#4406)
- codeberg.org/gruf/go-ffmpreg: v0.6.9 -> v0.6.10
- github.com/ncruces/go-sqlite3: v0.27.1 -> v0.28.0
- github.com/stretchr/testify: v1.10.0 -> v1.11.1
- github.com/tdewolff/minify/v2 v2.23.11 -> v2.24.2
- go.opentelemetry.io/otel{,/*}: v1.37.0 -> v1.38.0
- go.opentelemetry.io/contrib/*: v0.62.0 -> v0.63.0

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4406
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-04 15:29:27 +02:00
kim
5a54e7156b [performance] faster request id generation (#4405)
This uses a much faster method of generating request IDs using an atomically updated counter instead of a mutex lock and read of /dev/random.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4405
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-09-04 14:43:36 +02:00
karolis
9cb177cd8a style: add a missing whitespace (#4404)
Added a missing whitespace in callback page template.

Co-authored-by: Karolis Pocius <kpocius@gmail.com>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4404
Co-authored-by: karolis <karolis@noreply.codeberg.org>
Co-committed-by: karolis <karolis@noreply.codeberg.org>
2025-09-04 14:05:22 +02:00
mkljczk
3efb338ca9 [chore] fix copy-pasted comment (#4402)
# Description

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [ ] I/we have performed a self-review of added code.
- [ ] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4402
Co-authored-by: mkljczk <git@mkljczk.pl>
Co-committed-by: mkljczk <git@mkljczk.pl>
2025-08-31 11:42:42 +02:00
kim
380bfd0289 [bugfix] fix nootel metrics function signature (#4392)
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4392
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-08-24 20:01:47 +02:00
kim
383e41e3e5 [chore] bump go-structr to v0.9.9 (#4390)
this improves handling of zero value keys. not something we bump into often, but a useful fix to have in place.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4390
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-08-22 16:04:22 +02:00
kim
a79f83cbde [chore] update dependencies (#4386)
- codeberg.org/gruf/go-bytesize v1.0.3 -> v1.0.4
- codeberg.org/gruf/go-kv/v2 v2.0.6 -> v2.0.7
- codeberg.org/gruf/go-mutexes v1.5.2 -> v1.5.3
- codeberg.org/gruf/go-structr v0.9.7 -> v0.9.8
- codeberg.org/gruf/go-ffmpreg v0.6.8 -> v0.6.9
- github.com/tomnomnom/linkheader HEAD@2018 -> HEAD@2025

all of the above codeberg.org/gruf updates are in preparation for Go1.25, except for bytesize, and also ffmpreg which is a rebuild with the latest version of ffmpeg (v5.1.7)

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4386
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-08-21 16:41:50 +02:00
nicole mikołajczyk
8c619d51b5 [chore] bump golangci-lint version in CI, disable var-naming package name checks (#4372)
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

# Description

This PR bumps golangci-lint used by CI to the latest version and partially disables the `var-naming` rule, which complains about the `common` and `util` package names.

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [ ] I/we have performed a self-review of added code.
- [ ] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4372
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-08-21 15:57:25 +02:00
kim
1144ac037f [feature] add metrics for worker counts, and worker queue sizes (#4387)
should help to debug https://codeberg.org/superseriousbusiness/gotosocial/issues/4309

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4387
Reviewed-by: Daenney <daenney@noreply.codeberg.org>
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-08-20 18:14:00 +02:00
kim
3fad524089 [bugfix] when clearing media metadata, copy all streams not just first (#4375)
Updates our ffmpeg metadata clearing arguments to copy all streams when copying codecs, not just the first of each.

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4312

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4375
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-08-16 15:16:00 +02:00
kim
a6bb45e5e4 [bugfix] media CLI list missing thumbs and statics (#4379)
refactors some of the media CLI listing code, and updates it to include both attachment thumbnails and emoji static images, which previously were missing.

addresses https://codeberg.org/superseriousbusiness/gotosocial/issues/4370

though in a follow-up i'll add support for regenerating attachment thumbnails and emoji static images.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4379
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-08-16 15:13:30 +02:00
kim
e9b7e977a5 [performance] replace uses of fmt.Sprintf() with inlineable buildURL_() and buildPath_() functions (#4374)
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4374
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-08-14 14:09:06 +02:00
nicole mikołajczyk
12e3cb71c1 [bugfix] insert filter keywords/statuses into DB when creating new filters (#4376)
I don't see an issue for this, but the endpoint used for creating filters simply didn't store the filter keywords/statuses in the DB.

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4376
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-08-14 12:54:56 +02:00
nicole mikołajczyk
8e76c9ab57 [chore] return correct error message (#4377)
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4377
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-08-14 12:17:42 +02:00
nicole mikołajczyk
fb2ef90ec5 [feature] support blur filter action (#4371)
This pull request implements the `blur` value of `filter_action` for status filtering. It was introduced by Mastodon 4.4.0. [Related docs update](https://github.com/mastodon/documentation/pull/1620)

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4371
Reviewed-by: kim <gruf@noreply.codeberg.org>
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-08-13 13:23:42 +02:00
kim
7f8cb204cd [feature] 2fa management via CLI (#4368)
Adds 2FA management to the admin CLI. Also does some CLI refactoring so the functions we pass around are exported functions instead of changeable global variables.

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4320

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4368
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-08-13 12:24:40 +02:00
kim
1edc0f7b3c [chore] bump to code.superseriousbusiness.org/oauth2/v4@ssb-v4.5.3-2 (#4367)
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4367
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-08-12 16:04:30 +02:00
nicole mikołajczyk
660cf2c94c [feature] scheduled statuses (#4274)
An implementation of [`scheduled_statuses`](https://docs.joinmastodon.org/methods/scheduled_statuses/). Will fix #1006.

this is heavily WIP and I need to reorganize some of the code, working on this made me somehow familiar with the codebase and led to my other recent contributions
i told some fops on fedi i'd work on this so i have no choice but to complete it 🤷‍♀️
btw iirc my avatar presents me working on this branch

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4274
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-08-12 14:05:15 +02:00
tobi
cead741c16 [docs] Revamp trusted proxies warning a bit (#4365)
Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4352 by mentioning required headers in reverse proxy.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4365
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-08-11 16:23:55 +02:00
tobi
e565855540 [chore] pin to go 1.24.6 (#4364)
Pins our Go version to v1.24.6 for bugfixes etc.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4364
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-08-11 16:04:29 +02:00
kim
67100809b3 [chore] update dependencies (#4361)
- codeberg.org/gruf/go-kv/v2 v2.0.5 => v2.0.6
- github.com/coreos/go-oidc/v3 v3.14.1 => v3.15.0
- github.com/miekg/dns v1.1.67 => v1.1.68
- github.com/tdewolff/minify/v2 v2.23.9 => v2.23.11
- github.com/yuin/goldmark v1.7.12 => v1.7.13
- golang.org/x/crypto v0.40.0 => v0.41.0
- golang.org/x/image v0.29.0 => v0.30.0
- golang.org/x/net v0.42.0 => v0.43.0
- golang.org/x/sys v0.34.0 => v0.35.0
- golang.org/x/text v0.27.0 => v0.28.0
- modernc.org/sqlite v1.38.0 => v1.38.2

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4361
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-08-10 15:05:54 +02:00
kim
7af9117e0d [feature + performance] add JSON logging format (#4355)
# Description

Adds JSON logging as an optional alternative log output format. In the process this moves our log formatting itself into a separate subpkg to make it more easily modular, and improves caller name getting with some calling function name caching.

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4355
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-08-09 16:23:00 +02:00
daenney
96c05a90a2 chore: github/README update release month (#4359)
# Description

July is definitely over.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [ ] I/we have performed a self-review of added code.
- [ ] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4359
Co-authored-by: daenney <git@noreply.sourcery.dny.nu>
Co-committed-by: daenney <git@noreply.sourcery.dny.nu>
2025-08-06 13:43:24 +02:00
Jade Arson
f301bd5abf [feature/frontend] Add Ninety Eight theme (#4348)
This pull request adds a new theme that I've just put together after procrastinating for 7 or 8 months lol

I made this pull request mainly because tobi already considered adding it to GtS upstream 5 minutes after [I made a fedi post about it](https://gts.apicrim.es/@awoo/statuses/01K18MJ1SD56581TANEKAKA6GV) ^^" (does this technically count as "discussing the proposed change"? probably not-) (though to be fair, this shows a slightly older revision of the theme -- you can see the most current one on [one of my fedi accounts](https://gts.apicrim.es/@128293). (…also I think it's quite obvious that I took the Ecks Pee theme as a basis ><)

Co-authored-by: Jade Arson <awoo@wolfyja.de>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4348
Co-authored-by: Jade Arson <codeberg@wolfyja.de>
Co-committed-by: Jade Arson <codeberg@wolfyja.de>
2025-07-30 17:56:30 +02:00
kim
7e45168d33 [feature] add streaming of statuses and status updates to LOCAL / PUBLIC timelines (#4353)
This adds streaming of statuses and edits to LOCAL and PUBLIC timeline types. Note that in the future we should probably rearrange some of the surface code so we don't perform so many repeated mute and visibility checks on the same status in sequence.

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4342

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4353
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-07-30 17:54:07 +02:00
kim
ac032ff6ab [chore] bump codeberg.org/gruf/go-ffmpreg to v0.6.8 (#4349)
see: https://codeberg.org/gruf/go-ffmpreg/releases/tag/v0.6.8

nothing too exciting, though wasi-sdk-27 contains one or two (though many more to go) of nuno's wasi-libc string function simd optimizations which may make *some* difference

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4349
Reviewed-by: tobi <kipvandenbos@noreply.codeberg.org>
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-07-29 15:15:55 +02:00
kim
e3dfd88893 [performance] bump codeberg.org/gruf/go-kv to v2 (#4341)
updates our codeberg.org/gruf/go-kv log key-value formatting library to latest version, which comes with some maaaaaaajor speed boosts in the form of:
- very minimal reflect.Value{} usage
- caching prepared formatting functions per type

~~still a work-in-progress until i make a release tag on the go-kv repository, which itself is waiting on published benchmark results in the README and finishing writing some code comments~~

benchmarks so far show this to be ~3x faster than the "fmt" stdlib package on average, when run across a wide variety (106 different types) of test cases, while still creating more visually friendly log output and actually recursing down nested struct ptrs

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4341
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-07-29 09:23:20 +02:00
nicole mikołajczyk
30cd1cd9eb [chore] Only display report comment forwarding notice when reporting account is local (#4344)
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

This pull request implements xyz or fixes abc.

closes #(issue)
closes #(another issue)

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4344
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-07-28 14:38:31 +02:00
kim
c00cad2ceb [chore] bump dependencies (#4339)
- github.com/KimMachineGun/automemlimit v0.7.4
- github.com/miekg/dns v1.1.67
- github.com/minio/minio-go/v7 v7.0.95
- github.com/spf13/pflag v1.0.7
- github.com/tdewolff/minify/v2 v2.23.9
- github.com/uptrace/bun v1.2.15
- github.com/uptrace/bun/dialect/pgdialect v1.2.15
- github.com/uptrace/bun/dialect/sqlitedialect v1.2.15
- github.com/uptrace/bun/extra/bunotel v1.2.15
- golang.org/x/image v0.29.0
- golang.org/x/net v0.42.0

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4339
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-07-22 18:00:27 +02:00
Daenney
eb60081985 [chore/deps] Upgrade to go-sqlite 0.27.1 (#4334)
# Description

This brings some performance improvements and SQLite 3.50.3.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [ ] I/we have performed a self-review of added code.
- [ ] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4334
Co-authored-by: Daenney <git@noreply.sourcery.dny.nu>
Co-committed-by: Daenney <git@noreply.sourcery.dny.nu>
2025-07-18 11:56:40 +02:00
tobi
a4b54aa935 [feature] Add avif file support (#4331)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

This pull request implements support for reading avif images properly.

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4330

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4331
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-07-17 13:20:01 +02:00
nicole mikołajczyk
94cbe1120e [bugfix] use correct interaction type for pre-accepted interaction requests (#4325)
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

This pull request fixes `InteractionType` incorrectly set for pre-approved interaction requests.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4325
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-07-14 17:12:47 +02:00
tobi
a97a15fd10 [bugfix] Fix wrong default used for HidesCcPublicFromUnauthedWeb in migration (#4318)
🤦 Changed it in gtsmodel but not in the migration ohhh, oooh

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4318
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-07-09 17:43:36 +02:00
tobi
352353ce7a [chore/testing] Add env vars to skip testrig setup/teardown (#4317)
Add flags to skip local testrig db setup and teardown, to allow somewhat easier testing of migrations. Documents env vars available to the testrig.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4317
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-07-09 17:25:45 +02:00
tobi
dcfc9b7885 [feature] Use hidesToPublicFromUnauthedWeb and hidesCcPublicFromUnauthedWeb properties for web visibility of statuses (#4315)
This pull request implements two new properties on ActivityPub actors: `hidesToPublicFromUnauthedWeb` and `hidesCcPublicFromUnauthedWeb`.

As documented, these properties allow actors to signal their preference for whether or not their posts should be hidden from unauthenticated web views (ie., web pages like the GtS frontend, web apps like the Mastodon frontend, web APIs like the Mastodon public timeline API, etc). This allows remote accounts to *opt in* to having their unlisted visibility posts shown in (for example) the replies section of the web view of a GtS thread. In future, we can also use these properties to determine whether we should show boosts of a remote actor's post on a GtS profile, and that sort of thing.

In keeping with our stance around privacy by default, GtS assumes `true` for `hidesCcPublicFromUnauthedWeb` if the property is not set on a remote actor, ie., hide unlisted/unlocked posts by default. `hidesToPublicFromUnauthedWeb` is assumed to be `false` if the property is not set on a remote actor, ie., show public posts by default.

~~WIP as I still want to work on the documentation for this a bit.~~

New props are already in the namespace document: https://gotosocial.org/ns

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4315
Reviewed-by: kim <gruf@noreply.codeberg.org>
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-07-09 16:50:25 +02:00
kim
c8a4ce9a88 [performance] use our own typed value context types for Value() key checking to improve performance (#4316)
Replaces our gtscontext package context.Context handling with our own typed contexts instead of `context.WithValue()`.

I wrote a quick benchmark consisting of (printlns to stop the compiler optimizing instructions away):
```golang
func BenchmarkContexts(b *testing.B) {
	var receiving *gtsmodel.Account
	var requesting *gtsmodel.Account
	var otherIRIs []*url.URL

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			ctx := context.Background()

			ctx = gtscontext.SetBarebones(ctx)
			ctx = gtscontext.SetFastFail(ctx)
			ctx = gtscontext.SetDryRun(ctx)
			ctx = gtscontext.SetReceivingAccount(ctx, receiving)
			ctx = gtscontext.SetRequestingAccount(ctx, requesting)
			ctx = gtscontext.SetOtherIRIs(ctx, otherIRIs)

			if !gtscontext.Barebones(ctx) {
				println("oh no!")
			}

			if !gtscontext.IsFastfail(ctx) {
				println("oh no!")
			}

			if !gtscontext.DryRun(ctx) {
				println("oh no!")
			}

			if gtscontext.ReceivingAccount(ctx) != nil {
				println("oh no!")
			}

			if gtscontext.RequestingAccount(ctx) != nil {
				println("oh no!")
			}

			if len(gtscontext.OtherIRIs(ctx)) > 0 {
				println("oh no!")
			}
		}
	})
}
```

Before results:
```shell
kim @ ~/Projects/main/gts.4
--> go test -v -run=none -bench=.* -benchmem ./internal/gtscontext/ -count=5
goos: linux
goarch: amd64
pkg: code.superseriousbusiness.org/gotosocial/internal/gtscontext
cpu: AMD Ryzen 7 7840U w/ Radeon  780M Graphics
BenchmarkContexts
BenchmarkContexts-16            19050348                61.73 ns/op          288 B/op          6 allocs/op
BenchmarkContexts-16            18245772                61.71 ns/op          288 B/op          6 allocs/op
BenchmarkContexts-16            18853680                61.80 ns/op          288 B/op          6 allocs/op
BenchmarkContexts-16            18561621                62.67 ns/op          288 B/op          6 allocs/op
BenchmarkContexts-16            17819241                62.89 ns/op          288 B/op          6 allocs/op
PASS
ok      code.superseriousbusiness.org/gotosocial/internal/gtscontext    6.112s
```

After results:
```shell
kim @ ~/Projects/main/gts.4
--> go test -v -run=none -bench=.* -benchmem ./internal/gtscontext/ -count=5
goos: linux
goarch: amd64
pkg: code.superseriousbusiness.org/gotosocial/internal/gtscontext
cpu: AMD Ryzen 7 7840U w/ Radeon  780M Graphics
BenchmarkContexts
BenchmarkContexts-16            28038618                41.67 ns/op          144 B/op          6 allocs/op
BenchmarkContexts-16            26537552                42.50 ns/op          144 B/op          6 allocs/op
BenchmarkContexts-16            26720542                42.39 ns/op          144 B/op          6 allocs/op
BenchmarkContexts-16            27408031                43.15 ns/op          144 B/op          6 allocs/op
BenchmarkContexts-16            25597026                44.02 ns/op          144 B/op          6 allocs/op
PASS
ok      code.superseriousbusiness.org/gotosocial/internal/gtscontext    5.997s
```

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4316
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-07-09 01:38:33 +02:00
nicole mikołajczyk
07f61a13de [chore] update error message (#4311)
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

# Description

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4311
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-07-06 13:11:18 +02:00
kim
66e1ec14aa [chore] move status filtering from type converter (#4306)
This finalizes the moving status filtering out of the type converter, and into its own `./internal/filter/` subpkg :)

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4306
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-07-04 15:30:39 +02:00
nicole mikołajczyk
79914bdbf7 [bugfix] set correct scope for StatusFavePOSTHandler (#4310)
> **OAuth:** User token + `write:favourites`

https://docs.joinmastodon.org/methods/statuses/#favourite

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4310
Reviewed-by: kim <gruf@noreply.codeberg.org>
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-07-04 15:29:27 +02:00
agx
bf46b87343 [docs] Document STARTTLS behavior (#4301)
The docs currently state that sending via `localhost` unencrypted can work but that's only true when the SMTP server doesn't offer `STARTTLS`. Make that a bit more obvious.

Couldn't test the doc build as miniconda isn't in my distro and pip wouldn't find all dependencies.

# Description

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Co-authored-by: Guido Günther <agx@sigxcpu.org>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4301
Co-authored-by: agx <agx@noreply.codeberg.org>
Co-committed-by: agx <agx@noreply.codeberg.org>
2025-07-03 16:52:07 +02:00
kim
7a5144b4cc [bugfix] fix possible nil ptr if requester is nil (#4307)
closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4305

thank you https://codeberg.org/Xilefian !

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4307
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-07-02 21:40:43 +02:00
kim
4f2aa792b3 [performance] add statusfilter cache to cache calculated status filtering results (#4303)
this adds another 'filter' type cache, similar to the visibility and mute caches, to cache the results of status filtering checks. for the moment this keeps all the check calls themselves within the frontend typeconversion code, but i may move this out of the typeconverter in a future PR (also removing the ErrHideStatus means of propagating a hidden status).

also tweaks some of the cache invalidation hooks to not make unnecessary calls.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4303
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-07-01 16:00:04 +02:00
kim
8b0ea56027 [chore] update go dependencies (#4304)
- github.com/KimMachineGun/automemlimit v0.7.2 => v0.7.3
- github.com/gin-contrib/cors v1.7.5 => v1.7.6
- github.com/minio/minio-go/v7 v7.0.92 => v7.0.94
- github.com/spf13/cast v1.8.0 => v1.9.2
- github.com/uptrace/bun{,/*} v1.2.11 => v1.2.14
- golang.org/x/image v0.27.0 => v0.28.0
- golang.org/x/net v0.40.0 => v0.41.0
- code.superseriousbusiness.org/go-swagger v0.31.0-gts-go1.23-fix => v0.32.3-gts-go1.23-fix

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4304
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-06-30 15:19:09 +02:00
kim
7712885038 [chore] bumps ncruces/go-sqlite3 v0.26.1 => v0.26.3 (#4302)
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4302
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-06-30 14:30:56 +02:00
tobi
5fbaf5b7be [feature] Allow anchor href to work for footnotes, use ID prefix to avoid clashes (#4298)
Updates markdown parser + sanitizer to allow footnote anchors to work properly, with appropriate roles. Footnote anchor IDs and backrefs use the status ID as a prefix to avoid clashes, so that footnotes don't break when multiple footnoted statuses are rendered on the same page (eg., in a thread or on the account's home page).

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4296

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4298
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-06-30 12:56:50 +02:00
kim
39b11dbfb6 [bugfix] fix issues with postgres array serialization (#4295)
thank you to @kipvandenbos -erino for figuring this out!

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4295
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-06-26 14:17:47 +02:00
kim
700bd69828 [bugfix] move broken stage of filters migration into new migration (#4293)
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4293
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-06-25 20:22:50 +02:00
kim
996da6e029 [performance] filter model and database table improvements (#4277)
- removes unnecessary fields / columns (created_at, updated_at)
- replaces filter.context_* columns with singular filter.contexts bit field which should save both struct memory and database space
- replaces filter.action string with integer enum type which should save both struct memory and database space
- adds links from filter to filter_* tables with Filter{}.KeywordIDs and Filter{}.StatusIDs fields (this also means we now have those ID slices cached, which reduces some lookups)
- removes account_id fields from filter_* tables, since there's a more direct connection between filter and filter_* tables, and filter.account_id already exists
- refactors a bunch of the filter processor logic to save on code repetition, factor in the above changes, fix a few bugs with missed error returns and bring it more in-line with some of our newer code

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4277
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-06-24 17:24:34 +02:00
kim
9d5af6c3dc [bugfix] update the default configuration to not set a db type or address, to require explicitly setting it (#4228)
This updates the database defaults to remove a type or address. This is to help ensure we don't have any repeats of https://codeberg.org/superseriousbusiness/gotosocial/issues/4183, it means the user needs to explicitly configure these things core settings instead of relying on defaults.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4228
Reviewed-by: Daenney <daenney@noreply.codeberg.org>
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-06-24 12:32:52 +02:00
tobi
56d1248a85 [chore] Add info and reminder to save changes at the top of profile settings page (#4289)
Adds a little message at the top of the profile settings page to remind folks to click save after changing things.

Related to https://codeberg.org/superseriousbusiness/gotosocial/issues/4281

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4289
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-06-23 17:29:27 +02:00
kim
80191348ba [bugfix] fix status.Local sometimes being nil (#4285)
also comments-out a flaky test, (or at-least part of it), since it's testing a pkg part that is already tested.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4285
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-06-21 12:03:35 +02:00
tobi
38ff88f006 [bugfix] Queue implicit accepts *before* other side effects (#4282)
This PR just fiddles with the order in which we process status create / boost / fave side effects and implicit acceptances. The goal is to try to make sure the Accept message gets sent to a remote instance *before* the interaction with an implicitly accepted status.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4282
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-06-20 15:38:23 +02:00
nicole mikołajczyk
bfc8c31e5f [feature] Support incoming avatar/header descriptions (#4275)
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

# Description

Follow-up to #4270

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/3450

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4275
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-06-19 15:10:41 +02:00
nicole mikołajczyk
29d481d769 [bugfix] delete interaction requests when deleting account (#4278)
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

# Description

I recently noticed that pending interaction requests don't disappear on domain suspension.

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4278
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-06-19 10:21:03 +02:00
tobi
8b615391e5 [bugfix] Remove errant alsoKnownAs inline @context entry (#4280)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

Our extra `alsoKnownAs` inline `@context` entry was incorrect, and doesn't need to be included anyways as it's already present at the AS namespace context doc here: https://www.w3.org/ns/activitystreams. This PR just removes it :)

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/3883

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4280
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-06-18 13:39:09 +02:00
kim
b1c0eca1d8 [bugfix] improved mute checking for boosted statuses (#4276)
This unwraps and follows the boosted status to do a full mute check on the original.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4276
Reviewed-by: tobi <kipvandenbos@noreply.codeberg.org>
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-06-16 13:12:48 +02:00
nicole mikołajczyk
7d50aec6dc [feature] Outgoing federation of avatar/header descriptions (#4270)
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

# Description

This implementation is compatible with Iceshrimp.NET, Pleroma and Chuckya, which already support federated avatar/header descriptions. I will add support for incoming descriptions federation in this or another PR (depending on when this one gets merged).

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4270
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-06-15 12:38:01 +02:00
tobi
a9b2d4ee35 [feature] Handle retractions of domain permission subscription entries (#4261)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

This pull request adds logic for nicely handling retractions of entries from domain permission subscriptions.

See docs for how this works but basically retracted entries will either be removed (and possibly picked up by a lower-prio subscription), or orphaned (and then possibly adopted), depending on the config of the domain permission subscription.

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4101

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4261
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-06-15 12:36:51 +02:00
kim
76e7fd62d2 [performance] use faster pixel format matching function (#4271)
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4271
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-06-14 12:27:53 +02:00
tobi
726584287a [bugfix] Remove hardcoded "public" db schema assumption (#4269)
This pull request closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4257 by removing the hardcoded "public" schema assumption in the database migrations. Tested on a local postgres with both the default public schema, and with the connection string (gotosocial schema) mentioned in the issue. Both seem to work OK!

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4269
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-06-13 16:05:00 +02:00
nicole mikołajczyk
5717ce6f3c [chore] upgrade golangci-lint to v2.1.6 and migrate config (#4265)
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

# Description

Contribution guidelines link to the golangci-lint documentation for the up-to-date version rather than [the legacy v1 doc](https://golangci.github.io/legacy-v1-doc/), which uses a different configuration schema. I migrated the config using the `golangci-lint migrate` command, moved the comments, adjusted staticcheck config and ensured the rules still work.

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [ ] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4265
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-06-13 15:45:35 +02:00
tobi
fc074d2357 [bugfix/accessibility] Don't remove marker from unordered lists, recolor instead (#4268)
Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4195 by removing unnecessary styling.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4268
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-06-13 14:22:56 +02:00
tobi
933a9091eb [bugfix] Fix nil ptr dereffing instance acct outbox (#4267)
Well well well it was something silly, no surprise there!

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4266

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4267
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-06-13 14:08:25 +02:00
kim
e87681d433 [bugfix] process account delete synchronously to prevent OOM (#4260)
# Description

- updates account delete processing to handle side-effects synchronously to prevent OOM
- updates account delete processing to check more often if account.IsLocal() for certain deletes / side-effects
- ensures that mutes get removed from database on delete

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4260
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-06-11 11:38:10 +02:00
kim
d7f967cbb5 [feature] configurable maximum thumbnail dimensions (#4258)
- adds configuration for thumbnail maximum dimensions with warning on exceeding recommendations
- moves the media configuration vars into their own sub-struct
- replaces the configuration flag funcs with simple string consts

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4258
Reviewed-by: tobi <kipvandenbos@noreply.codeberg.org>
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-06-10 15:43:31 +02:00
tobi
1dc79c9586 [chore] Update interactionPolicy sub-policy parsing in line with documented defaults (#4229)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

Brings our parsing of unset sub-policies in line with the defaults documented here: https://docs.gotosocial.org/en/v0.19.1/federation/interaction_policy/#defaults-per-sub-policy

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4146

Part of https://codeberg.org/superseriousbusiness/gotosocial/issues/4026

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4229
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-06-10 14:29:42 +02:00
kim
4ad17788cd [chore] update to modernc.org/sqlite v1.38.0 with our concurrency workaround (#4256)
see: https://gitlab.com/cznic/sqlite/-/tags/v1.38.0
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4256
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-06-10 13:19:18 +02:00
nicole mikołajczyk
d3f2c2c765 [bugfix] fix existing statuses with invalid visibility (#4253)
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

# Description

Related to #4252. This fixes existing statuses with visibility enum set to 0, if any exist on the server, by replacing their visibility to direct (to not leak them outside the intended scope).

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4253
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-06-10 12:16:09 +02:00
Oliver Calder
153f6feecd [docs] update protocol arg help text to reflect documentation (#4250)
The current documentation states that the `protocol` configuration
option should only be changed to `http` for local testing, and that even
if running behind a reverse proxy, `https` should be used.

https://docs.gotosocial.org/en/latest/configuration/general/

As such, update the `protocol` option help text so that it does not
suggest using `http` when running behind a reverse proxy.

Signed-off-by: Oliver Calder <oliver@calder.dev>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4250
Co-authored-by: Oliver Calder <oliver@calder.dev>
Co-committed-by: Oliver Calder <oliver@calder.dev>
2025-06-10 12:14:46 +02:00
Daenney
37f9a9fa94 [chore] Upgrade to SQLite 3.50.1 (#4255)
# Description

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [ ] I/we have performed a self-review of added code.
- [ ] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4255
Co-authored-by: Daenney <daenney@noreply.codeberg.org>
Co-committed-by: Daenney <daenney@noreply.codeberg.org>
2025-06-10 01:08:57 +02:00
nicole mikołajczyk
3f1c3c0dac [bugfix] return 422 for invalid status visibility (#4252)
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

# Description

closes #4247

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4252
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-06-09 16:26:49 +02:00
nicole mikołajczyk
54a0af34fb [feature] enable footnote extension for markdown parser (#4251)
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

# Description

This enables footnote support which is mentioned as allowed in the [user guide](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/docs/user_guide/posts.md#input-types). The regression was reported on Matrix.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [sort of] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4251
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-06-09 16:00:25 +02:00
Nicole Mikołajczyk
bd4fe7081e [docs] change ID links in ToC to match goldmark parser behavior (#4223)
Signed-off-by: Nicole Mikołajczyk <git@mkljczk.pl>

# Description

I'm not sure if this should be handled this way, but some of the TOC links don't work on Forgejo due to, I guess, the Markdown parser behavior. This, however, makes them not work on GitHub

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4223
Co-authored-by: Nicole Mikołajczyk <git@mkljczk.pl>
Co-committed-by: Nicole Mikołajczyk <git@mkljczk.pl>
2025-06-09 12:35:37 +02:00
nicole mikołajczyk
01e3765268 [feature] Add fields introduced in Mastodon 4.4.0 to /api/v2/instance response (#4240)
# Description

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4240
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-06-09 12:32:14 +02:00
tobi
32738d83a8 [bugfix] Update GetURL to extract url from Link objects with href (#4249)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

This pull request updates our parsing of the `url` property in incoming ActivityPub items to also include Link items, and not just bare URIs.

The first discovered url is still used as the *gtsmodel.Account or *gtsmodel.Status `url` property, so this change only really affects our dereference URL anti-spoof check thingy.

~~Should fix https://codeberg.org/superseriousbusiness/gotosocial/issues/4248 but I need to run it and test it myself first to be sure.~~

Fixes https://codeberg.org/superseriousbusiness/gotosocial/issues/4248

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4249
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-06-09 12:32:00 +02:00
kim
b13a6437ff [chore] move s3 storage key prefixing into the storage library itself (#4246)
This is just a useful feature that it seemed more semantically correct to have in the storage library itself! Still, thank you to @vdyotte for the original change :)

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4246
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-06-06 16:35:39 +02:00
kim
77eddea3af [chore] updates code.superseriousbusiness.org/oauth2/v4 to ssb-v4.5.3-1 (#4245)
A brief note on the above change: Go does not seem to like version tagging outside of `v?[0-9\.]` formatting, so it translates `ssb-v4.5.3-1` to `v4.5.4-0.20250606121655-9d54ef189d42` and as such sees it as a "downgrade" compared to the previous `v4.9.0`. which functionally isn't a problem, everything still behaves as it should, but it means people can't just run `go get repo@latest` for this particular dependency.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4245
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-06-06 15:14:37 +02:00
tobi
a37dd59d1f [chore] blocklist -> allowlist config typo fix (#4242)
D'oh! Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4239

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4242
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-06-05 11:30:13 +02:00
tobi
118d4e4d03 [bugfix] Assume default code challenge method of s256 (#4241)
Bumps our oauth2 dependency, and uses *default* code challenge method of S256 instead of plain.

Fixes https://codeberg.org/superseriousbusiness/gotosocial/issues/4238

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4241
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-06-05 11:29:36 +02:00
tobi
43f1c6d872 [feature] Add config option to expose custom emojis without auth (#4233)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

Does as it says on the tin! Should make things a bit easier for clients that don't provide an access token to the custom emojis endpoint.

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/2430

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4233
Reviewed-by: Daenney <daenney@noreply.codeberg.org>
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-06-03 23:30:42 +02:00
Emelia
be6d80c020 [chore] Remove insecure PKCE Code Challenge Method for plain (#4232)
# Description

As I noted in https://codeberg.org/superseriousbusiness/gotosocial/pulls/2224 the PKCE code challenge method of "plain" is insecure and its usage is not recommend. In Mastodon and Hollo, we do not support it, as indicated by the `code_challenge_methods_supported` value here: https://mastodon.social/.well-known/oauth-authorization-server

This pull request removes the support for PKCE code challenge method "plain".

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

I do get test failures locally, due to file sizes for media being different, but that's definitely unrelated to this change, as far as I can tell there is zero test coverage this part of the GTS code.

Co-authored-by: Emelia Smith <ThisIsMissEm@users.noreply.github.com>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4232
Co-authored-by: Emelia <thisismissem@noreply.codeberg.org>
Co-committed-by: Emelia <thisismissem@noreply.codeberg.org>
2025-06-03 10:04:15 +02:00
tobi
6d511d696b [bugfix] Fix nil ptr for audio attachments with no preview in web (#4227)
Fixes a cheeky little nil pointer bug that I wrote.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4227
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-06-02 12:52:51 +02:00
nicole mikołajczyk
5097e6d278 [feature] /api/v1/follow_requests/outgoing (#4224)
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

# Description

This pull request adds a new endpoint which returns a list of pending follow requests requested by the user. The test is adapted from the GET /api/v1/follow_requests test.

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4224
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
2025-06-02 11:46:17 +02:00
Nicole Mikołajczyk
ee180a2359 [bugfix] fix GetAccountFollowRequestingIDs query (#4222)
Signed-off-by: Nicole Mikołajczyk <git@mkljczk.pl>

# Description

This pull request fixes a bug encountered when playing around with GTS code.

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4222
Co-authored-by: Nicole Mikołajczyk <git@mkljczk.pl>
Co-committed-by: Nicole Mikołajczyk <git@mkljczk.pl>
2025-06-01 11:24:04 +02:00
famfo
025ca487cf [feature/internal/httpclient] add option to configure outgoing protocol (#4134)
# Description

Adds a configuration option to set the outgoing transport of HTTP requests for testing purposes.

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.
  - Note: `go fmt` yes, golangci-lint fails, can't load any configuration

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4134
Reviewed-by: kim <gruf@noreply.codeberg.org>
Co-authored-by: famfo <famfo@famfo.xyz>
Co-committed-by: famfo <famfo@famfo.xyz>
2025-05-31 19:15:39 +02:00
kim
faed35c938 [performance] cache mute check results (#4202)
This separates our the user mute handling from the typeconverter code, and creates a new "mutes" filter type (in a similar vein to the visibility filter) subpkg with its own result cache. This is a heavy mix of both chore given that mute calculation shouldn't have been handled in the conversion to frontend API types, and a performance bonus since we don't need to load and calculate so many things each time, just the single result each time with all necessary invalidation handled by database cache hooks.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4202
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-31 17:30:57 +02:00
kim
a82d574acc [feature] make client-side nonce calculation multi-threaded (#4219)
# Description

Thank you in part to f0x for nerd-sniping me into banging this together :p

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4219
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-31 13:45:32 +02:00
Daenney
3b46eb6a9e [chore] Upgrade to SQLite 3.50 (#4218)
# Description

Upgrades ncruces/go-sqlite3 to 0.26 which includes SQLite 3.50.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [ ] I/we have performed a self-review of added code.
- [ ] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4218
Co-authored-by: Daenney <daenney@noreply.codeberg.org>
Co-committed-by: Daenney <daenney@noreply.codeberg.org>
2025-05-31 13:43:33 +02:00
Nicole Mikołajczyk
d9e8d844e1 [docs] fix typo in swagger description for ListsGETHandler (#4217)
Signed-off-by: Nicole Mikołajczyk <git@mkljczk.pl>

# Description

This pull request fixes a typo.

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [ ] I/we have performed a self-review of added code.
- [ ] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4217
Co-authored-by: Nicole Mikołajczyk <git@mkljczk.pl>
Co-committed-by: Nicole Mikołajczyk <git@mkljczk.pl>
2025-05-31 13:42:58 +02:00
vdyotte
0e698a49fb [feature] Add S3 key prefix (#4200)
Been running these changes on on my live instance without any issues as far as I can tell. It's been playing nice with multiple instances in the same bucket.

# Description

This lets users prefix their object storage files.
Useful for when you want to host multiple GTS instances inside
the same bucket. Providers like Backblaze limit the number of buckets
you can have on your account so grouping by prefix may be more desirable
in this situation.

closes #1371

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4200
Co-authored-by: vdyotte <vdyotte@gmail.com>
Co-committed-by: vdyotte <vdyotte@gmail.com>
2025-05-30 14:12:29 +02:00
tobi
3ff6f6e421 [bugfix/frontend] Fix text-shadow on dark mode themes (#4216)
Just deals with a few remaining straggler bits of css fuckery that I introduced in https://codeberg.org/superseriousbusiness/gotosocial/pulls/4201

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4216
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-30 12:14:17 +02:00
tobi
2c73bb3602 [feature/frontend] Respect color scheme preference for highlighted code blocks (#4201)
That's it! It just conditionally imports prism light or prism dark depending on the theme.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4201
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-30 11:06:08 +02:00
tobi
6c1b674278 [feature/frontend] Add four new monospace themes (#4199)
This pull request adds four new themes with auto light/dark switching options too!

Tested for color contrast etc in firefox with all three local test rig accounts.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4199
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-29 11:48:34 +02:00
kim
f3c4ea0106 [chore] thread_id migration tweaks (#4198)
# Description

- add a `migrations run` sub command to allow simply starting / stopping the db service, useful if you want to run *only* the migrations, both for testing or if you have a speedier box you want to run them on
- tweaks to log messages
- moved more stages outside of transactions, on sqlite if the transactions were getting too lengthy it could occasionally show an `sqlite: disk i/o error`

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4198
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-28 11:36:14 +02:00
kim
143febb318 [chore] update dependencies (#4196)
- go.opentelemetry.io/contrib/exporters/autoexport v0.60.0 -> v0.61.0
- go.opentelemetry.io/contrib/instrumentation/runtime v0.60.0 -> v0.61.0

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4196
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-26 16:13:55 +02:00
kim
311d9a1697 [chore] migration to update statuses.thread_id to be notnull (#4160)
# Description

This is quite a complex database migration that updates the `statuses.thread_id` column to be notnull, in order that statuses always be threaded, which will be useful in various pieces of upcoming work. This is unfortunately a migration that acts over the entire statuses table, and is quite complex in order to ensure that all existing statuses get correctly threaded together, and where possible fix any issues of statuses in the same thread having incorrect thread_ids.

TODO:
- ~~update testrig models to all be threaded~~
- ~~update code to ensure thread_id is always set~~
- ~~run on **a copy** of an sqlite production database~~
- ~~run on **a copy** of a postgres production database~~

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4160
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-26 15:33:42 +02:00
tobi
fd64a1e264 [feature] Add "Instance Info" settings panel section, with domain blocks + allows (#4193)
This pull request adds a new read-only, user-level "instance info" section to the settings panel, which presents api/v2/instance info in a nice readable format, and also gives the user authenticated access to the blocklist and allowlist of the domain.

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/3711
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4193
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-26 13:28:55 +02:00
kim
326e04283a [feature] update proof-of-work to allow setting required rounds (#4186)
# Description

This updates our proof-of-work middleware, NoLLaMas, to work on a more easily configurable algorithm (thank you f0x for bringing this to my attention!). Instead of requiring that a solution with pre-determined number of '0' chars be found, it now pre-computes a result with a pre-determined nonce value that it expects the client to iterate up-to. (though with some level of jitter applied, to prevent it being too-easily gamed). This allows the user to configure roughly how many hash-encode rounds they want their clients to have to complete.

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4186
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-26 11:57:50 +02:00
kim
b6ff55662e [chore] update dependencies (#4188)
Update dependencies:
- github.com/gin-gonic/gin v1.10.0 -> v1.10.1
- github.com/gin-contrib/sessions v1.10.3 -> v1.10.4
- github.com/jackc/pgx/v5 v5.7.4 -> v5.7.5
- github.com/minio/minio-go/v7 v7.0.91 -> v7.0.92
- github.com/pquerna/otp v1.4.0 -> v1.5.0
- github.com/tdewolff/minify/v2 v2.23.5 -> v2.23.8
- github.com/yuin/goldmark v1.7.11 -> v1.7.12
- go.opentelemetry.io/otel{,/*} v1.35.0 -> v1.36.0
- modernc.org/sqlite v1.37.0 -> v1.37.1

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4188
Reviewed-by: Daenney <daenney@noreply.codeberg.org>
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-22 16:27:55 +02:00
tobi
20aad9be0f [chore/woodpecker] don't make test depend on lint (#4189)
Just remove the dependency `test` has on `lint`, as it's not actually dependent on it, and has different triggers.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4189
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-22 15:54:58 +02:00
tobi
00e58c60cd [feature] Add ListenBrainz functionality on the web view (#4184)
This pull request adds a very simple ad-hoc ListenBrainz widget to the frontend web view, with progressive enhancement (in all fail states it just falls back to rendering the field as normal).

This necessitated adding the ListenBrainz API endpoint to the `connect-src` part of our Content-Security-Policy header. We might want to tweak this to only add that endpoint to `connect-src` for profiles, and then only for profiles that include a ListenBrainz field, but this would require significant dicking about with the middleware, and checks inside the app logic, such that it might not be worthwhile (after all, we control all the scripts right now anyway).

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4184
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-22 12:34:39 +02:00
Daenney
d5c9c4adc1 [chore] Upgrade to Go 1.24 (#4187)
* Set `go.mod` to 1.24 now that it's been out for 3 months.
* Update all the test to use `testing.T.Context()`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4187
Co-authored-by: Daenney <git@noreply.sourcery.dny.nu>
Co-committed-by: Daenney <git@noreply.sourcery.dny.nu>
2025-05-22 12:26:11 +02:00
tobi
ec4d4d0115 [feature] Allow exposing allows, implement /api/v1/domain_blocks and /api/v1/domain_allows (#4169)
- adds config flags `instance-expose-allowlist` and `instance-expose-allowlist-web` to allow instance admins to expose their allowlist via the web + api.
- renames `instance-expose-suspended` and `instance-expose-suspended-web` to  `instance-expose-blocklist` and `instance-expose-blocklist-web`.
- deprecates the `suspended` filter on `/api/v1/instance/peers` endpoint and adds `blocked` and `allowed` filters
- adds the `flat` query param to `/api/v1/instance/peers` to allow forcing return of a flat list of domains
- implements `/api/v1/instance/domain_blocks` and `/api/v1/instance/domain_allows` endpoints with or without auth depending on config
- rejigs the instance about page to include a general section on domain permissions, with block and allow subsections (and appropriate links)

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/3847
Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4150

Prerequisite to https://codeberg.org/superseriousbusiness/gotosocial/issues/3711

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4169
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-20 11:47:40 +02:00
kim
3a29a59e55 [bugfix] fix case of failed timeline preload causing lockups (#4182)
- moves preloader Done() function calling to be handled entirely by the preloader, not the caller
- adds tests for multiple preload success / failure / clear states

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4182
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-17 11:52:49 +00:00
kim
3cff4b2d7d [chore] various federatingdb tweaks (#4178)
after seeing a potential reported federating worker lockup i decided to start digging into the federatingdb code. this PR encompasses:
- removes one of our last unused interface types `federatingdb.DB{}`, replacing it with a struct type `*federatingdb.DB{}`
- in `transport.dereferenceLocal()` differentiates between an unsupported lookup type and ErrNoEntries to reduce unnecessary calls, and reduce potential lockups that may occur while trying to call our own endpoints that then call `federatingdb.Lock()`
- removes a bunch of the locks on follow state changes since the DB already synchronizes that
- removes the unnecessary `pub.Clock{}` struct field and type passed to the transport controller

frankly it would be great if we could remove the locking in `federatingdb.Lock()` and instead handle it ourselves as it gets very confusing trying to figure out what functions will have locks held. but i guess that's one for when we move further away from the go-fed/activity/pub package usage.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4178
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-15 09:40:48 +00:00
Phil Hagelberg
cfe6336b6e [chore] Change default database in example config to sqlite, update docs. (#4174)
As discussed in Matrix chat.

* Change DB in example config to sqlite.
* Clarify config settings which only apply to postgres.
* Update getting started docs; no need to change example config any more.
* In "single board computers" mention SD card corruption risk.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [X] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [X] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [X] I/we have not leveraged AI to create the proposed changes.
- [X] I/we have performed a self-review of added code.
- [X] I/we have made any necessary changes to documentation.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4174
Co-authored-by: Phil Hagelberg <phil@hagelb.org>
Co-committed-by: Phil Hagelberg <phil@hagelb.org>
2025-05-14 13:25:52 +00:00
Jackson
3ba49aed45 [feature] Configurable max profile fields (#4175)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

Profile fields, right? So I made them a configurable amount and show them on the instance features. Closes #1876

All changes I did are described in the commits. I tried to cover as much as possible, but I don't know this codebase to know what I've missed. I have tested it manually and it works (settings page, `/api/v1/instances`, server-side validation).

Not done:
- An "Add profile fields" button, so that instances with a high profile fields count (e.g. 100) aren't an issue when trying to skip the profile fields (in some form, accessibility)
- Updating the swagger docs that specify a specific amount of profile fields for the updating endpoint (not sure how to proceed with that)
- Unchecked checklist items

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [X] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [X] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [X] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [X] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [X] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Notes about checklist:
- ["Approval" to work on this reference](https://matrix.to/#/!mlPctfMHjyopbOnliM:superseriousbusiness.org/$P0Z1Qmny6GNIgxhre69gll8KSD690HC8nVvNpXmu3nU?via=superseriousbusiness.org&via=matrix.org&via=tchncs.de)
- `golangci-lint run` output ignored due to complaining about ffmpeg and some other code I didn't touch

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4175
Reviewed-by: kim <gruf@noreply.codeberg.org>
Co-authored-by: Jackson <jackson@jacksonchen666.com>
Co-committed-by: Jackson <jackson@jacksonchen666.com>
2025-05-14 13:25:21 +00:00
tobi
ca12742a7a [chore] Deprecate with_approval, always (client API), approvalRequired, always (fedi API) (#4173)
This pull request deprecates `with_approval` and `always` on the client API side, and `approvalRequired` and `always` on the fedi API side, replacing them with `automatic_approval` and `manual_approval` and `automaticApproval` and `manualApproval`, respectively.

Back-compat is kept with these deprecated fields, and they're still serialized to the client API and fedi APIs respectively, in addition to the new non-deprecated properties.

This will stay the case until v0.21.0 when they'll be removed.

For the sake of not doing a massive database migration, the fields are still named `Always` and `WithApproval` in storage. I think this is probably fine!

Part of https://codeberg.org/superseriousbusiness/gotosocial/issues/4026
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4173
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-13 14:48:11 +00:00
tobi
5925644ad3 [chore] Update woodpecker to catch len(fromJSON(CI_PIPELINE_FILES)) == 0 (#4177)
This'll hopefully catch some straggler occurrences of the tests not wanting to run.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4177
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-13 11:23:30 +00:00
tobi
3fedff3a5a [chore] Tidy up previous interaction policy migrations (#4171)
This pull request tidies up some previous migrations by making sure there's a proper snapshot in the migrations folder of what interaction policies looked like at the time the migration was written, rather than using the moving target `internal/gtsmodel`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4171
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-12 16:22:45 +00:00
Daenney
d3c67ad642 [chore] Use Codeberg API for get_latest_snapshot (#4151)
# Description

Switches the script to use the Codeberg API to retrieve the hash.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [ ] I/we have performed a self-review of added code.
- [ ] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4151
2025-05-11 15:14:06 +00:00
tobi
8480a75808 [feature] Notify accounts when a status they've interacted with has been edited (#4157)
This pull request adds sending notifications to local accounts that have interacted with a status, if we receive or create a new edit for that status.

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/3991
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4157
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-11 13:38:13 +00:00
Iivari Äikäs
6b6946f42a [bugfix] Fix a11y property warning from authorization page (#4166)
Use correct input-field identifier for authorization page email label. This seemed to be only instance where label was broken, other labels either had correct for-identifier or enclosed the input which they are labeling.

closes #4165

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4166
Co-authored-by: Iivari Äikäs <iivari.aikas@gmail.com>
Co-committed-by: Iivari Äikäs <iivari.aikas@gmail.com>
2025-05-11 11:51:30 +00:00
Taavi Väänänen
61137e6c41 [bugfix] Remove unnecessary whitespace from trusted-proxies warning (#4168)
closes #4167

Co-authored-by: Taavi Väänänen <hi@taavi.wtf>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4168
Co-authored-by: Taavi Väänänen <codeberg@taavi.wtf>
Co-committed-by: Taavi Väänänen <codeberg@taavi.wtf>
2025-05-11 11:50:57 +00:00
Frederic Thevenet
7bd4bed558 [feature/frontend] Add id attributes to 'about user' section to allow for reordering using css (#4164)
# Description

This pull request adds `id` attributes to elements in the "About" section of the user page so that it is easy to look them up using css.
It also move the screen reader only elements for some these so that they are re-ordered alongside their parent element.

closes #4163

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4164
Co-authored-by: Frederic Thevenet <thevenet.fred@free.fr>
Co-committed-by: Frederic Thevenet <thevenet.fred@free.fr>
2025-05-10 19:46:41 +00:00
kim
d2f13e7564 [chore] update direct Go dependencies (#4162)
- update gruf/go-stroage v0.2.0 -> v0.2.1
- update KimMachineGun/automemlimit v0.7.1 -> v0.7.2
- update miekg/dns v1.1.65 -> v1.1.66
- update ncruces/go-sqlite3 v0.25.1 -> v0.25.2
- update spf13/cast v1.7.1 -> v1.8.0
- update tdewolff/minify/v2 v2.23.1 -> v2.23.5
- update x/crypto v0.37.0 -> v0.38.0
- update x/image v0.26.0 -> v0.27.0
- update x/net v0.39.0 -> v0.40.0
- update x/oauth2 v0.29.0 -> v0.30.0
- update x/sys v0.32.0 -> v0.33.0
- update x/text v0.24.0 -> v0.25.0

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4162
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-10 14:27:25 +00:00
tobi
8c1511a494 [chore] Poke at bundle_licenses.sh a bit to make the output slightly easier on the eye (#4159)
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4159
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-09 16:14:10 +00:00
kim
cfa83fb44c [chore] include a monstrous all_licenses.txt in our web assets (#4155)
Should fix https://codeberg.org/superseriousbusiness/gotosocial/issues/4153

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4155
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-09 10:32:20 +00:00
tobi
700b7eaab7 [feature] Add extra opengraph meta tags (#4154)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

Update our opengraph meta tag code stuff:

- Use `audio` and `video` types where appropriate.
- Include fall back to `image` types.
- Include `twitter:card=summary` or `twitter:card=summary_large_image` where appropriate (closes https://codeberg.org/superseriousbusiness/gotosocial/issues/2776)
- Include avatar description where possible.
- Include mime type for media.
- Set `modified_time` properly based on latest edit time.

Examples

Status with one image attachment, that's been edited:

```html
<meta property="og:locale" content="en">
<meta property="og:type" content="article">
<meta property="og:title" content="Post by Kip Van Den Bos, salad enjoyer, @tobi@goblin.technology">
<meta property="og:url" content="https://goblin.technology/@tobi/statuses/01JE3BQPNHWNHSNM0KS78X321Q">
<meta property="og:site_name" content="goblin.technology">
<meta property="og:description" content="cowards: &#34;I&#39;ll be a few minutes late, sorry!&#34; me:">
<meta property="og:article:publisher" content="https://goblin.technology/@tobi">
<meta property="og:article:author" content="https://goblin.technology/@tobi">
<meta property="og:article:modified_time" content="2025-04-22T07:24:49.773Z">
<meta property="og:article:published_time" content="2024-12-02T09:37:58.449Z">
<meta property="og:image" content="https://goblin.technology/fileserver/016T5Q3SQKBT337DAKVSKNXXW1/attachment/original/01JE3BPJ1TGMV6H6E8VY0ED5XA.png">
<meta property="og:image:type" content="image/png">
<meta property="og:image:width" content="1224">
<meta property="og:image:height" content="368">
<meta property="og:image:alt" content="Screenshot of a signal conversation where I wrote &#34;Just gonna smash out a quick poo&#34; and my friend responded with a sad face.">
<meta property="og:image" content="https://goblin.technology/fileserver/016T5Q3SQKBT337DAKVSKNXXW1/attachment/original/01J4YBM16ES6C1ENKZC8MC04BD.gif">
<meta property="og:image:type" content="image/gif">
<meta property="og:image:width" content="38">
<meta property="og:image:height" content="49">
<meta property="og:image:alt" content="Avatar for tobi: A 90&#39;s style gif of a black and white skull chattering happily.">
<meta property="og:image" content="https://goblin.technology/fileserver/01BPSX2MKCRVMD4YN4D71G9CP5/attachment/original/01J387PFPNKQWWNY9YQM67WA1T.gif">
<meta property="og:image:type" content="image/gif">
<meta property="og:image:alt" content="Little green peglin goblin bouncing happily.">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://goblin.technology/fileserver/016T5Q3SQKBT337DAKVSKNXXW1/attachment/original/01JE3BPJ1TGMV6H6E8VY0ED5XA.png">
<meta name="twitter:image:alt" content="Screenshot of a signal conversation where I wrote &#34;Just gonna smash out a quick poo&#34; and my friend responded with a sad face.">
```

Status with one audio file (with thumbnail):

```html
<meta property="og:locale" content="en">
<meta property="og:type" content="article">
<meta property="og:title" content="Post by Kip Van Den Bos, salad enjoyer, @tobi@goblin.technology">
<meta property="og:url" content="https://goblin.technology/@tobi/statuses/01JSV5BQ585HB4R8NPK4ANTG91">
<meta property="og:site_name" content="goblin.technology">
<meta property="og:description" content="service top anthem imo">
<meta property="og:article:publisher" content="https://goblin.technology/@tobi">
<meta property="og:article:author" content="https://goblin.technology/@tobi">
<meta property="og:article:modified_time" content="2025-04-27T08:21:00.712Z">
<meta property="og:article:published_time" content="2025-04-27T08:21:00.712Z">
<meta property="og:audio" content="https://goblin.technology/fileserver/016T5Q3SQKBT337DAKVSKNXXW1/attachment/original/01JSV5AJ4RF3E6DATCSW8SAY93.mp3">
<meta property="og:audio:secure_url" content="https://goblin.technology/fileserver/016T5Q3SQKBT337DAKVSKNXXW1/attachment/original/01JSV5AJ4RF3E6DATCSW8SAY93.mp3">
<meta property="og:audio:type" content="audio/mpeg">
<meta property="og:audio:alt" content="Sanctified by Nine Inch Nails, from Pretty Hate Machine">
<meta property="og:image" content="https://goblin.technology/fileserver/016T5Q3SQKBT337DAKVSKNXXW1/attachment/small/01JSV5AJ4RF3E6DATCSW8SAY93.webp">
<meta property="og:image:type" content="image/webp">
<meta property="og:image:width" content="500">
<meta property="og:image:height" content="500">
<meta property="og:image:alt" content="Sanctified by Nine Inch Nails, from Pretty Hate Machine">
<meta property="og:image" content="https://goblin.technology/fileserver/016T5Q3SQKBT337DAKVSKNXXW1/attachment/original/01J4YBM16ES6C1ENKZC8MC04BD.gif">
<meta property="og:image:type" content="image/gif">
<meta property="og:image:width" content="38">
<meta property="og:image:height" content="49">
<meta property="og:image:alt" content="Avatar for tobi: A 90&#39;s style gif of a black and white skull chattering happily.">
<meta property="og:image" content="https://goblin.technology/fileserver/01BPSX2MKCRVMD4YN4D71G9CP5/attachment/original/01J387PFPNKQWWNY9YQM67WA1T.gif">
<meta property="og:image:type" content="image/gif">
<meta property="og:image:alt" content="Little green peglin goblin bouncing happily.">
<meta name="twitter:card" content="summary">
```

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4154
Reviewed-by: Daenney <daenney@noreply.codeberg.org>
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-08 11:11:25 +00:00
kim
4c96e2571d [feature] make nollamas difficulty configurable (#4119)
Makes the NoLLaMas proof-of-work scraper deterrence difficulty configurable.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4119
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-07 11:59:39 +00:00
tobi
1f0c261fd2 [bugfix] Fix indentation on multi-line alt text in web view (#4149)
This pull request closes https://codeberg.org/superseriousbusiness/gotosocial/issues/3403 by searching for alt or title attributes in HTML, looking for the shortest indent (if any) at the start of multiline content of said attributes, and remove that shortest indent from each line. This is a bit more fiddly than the "easy" way of doing it, but it has the advantage that it preserves user-added indents at the start of lines of alt text.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4149
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-07 11:48:21 +00:00
tobi
7e105f98ed [chore/frontend] Put fonts in folders, update ecks pee to atkinson-hyperlegible next/mono (#4148)
Juggles our fonts around a bit to use subdirs for font families, and also updates atkinson hyperlegible to atkinson hyperlegible next, which includes monospace fonts.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4148
Reviewed-by: Daenney <daenney@noreply.codeberg.org>
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-07 09:39:46 +00:00
filipesm
b2a469d6b6 [docs] Clarify that boosting local-only posts maintains local-only status, in the documentation (#4145)
# Description

I would also really like to know if local-only posts can be accessed publicly via URL? I can add it to the PR when I know.

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4145
Co-authored-by: filipesm <hello@filipesm.eu>
Co-committed-by: filipesm <hello@filipesm.eu>
2025-05-06 20:28:47 +00:00
kim
6acf56cde9 [feature] support nested configuration files, and setting ALL configuration variables by CLI and env (#4109)
This updates our configuration code generator to now also include map marshal and unmarshalers. So we now have much more control over how things get read from pflags, and stored / read from viper configuration. This allows us to set ALL configuration variables by CLI and environment now, AND support nested configuration files. e.g.

```yaml
advanced:
    scraper-deterrence = true

http-client:
    allow-ips = ["127.0.0.1"]
```

is the same as

```yaml
advanced-scraper-deterrence = true

http-client-allow-ips = ["127.0.0.1"]
```

This also starts cleaning up of our jumbled Configuration{} type by moving the advanced configuration options into their own nested structs, also as a way to show what it's capable of. It's worth noting however that nesting only works if the Go types are nested too (as this is how we hint to our code generator to generate the necessary flattening code :p).

closes #3195

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4109
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-06 15:51:45 +00:00
tobi
7d74548a91 [docs] Various little docs updates (#4144)
Just various little docs fixes, including adding registry prefix `docker.io/` to Docker container tags.

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4126

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4144
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-06 14:28:40 +00:00
tobi
ebf64eb0db [bugfix] fix statuses not being notified (#4143)
It was the colon what done it muy lorde

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4143
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-06 14:19:58 +00:00
kim
8264b63337 [bugfix] ensure timeline limit query is respected (#4141)
# Description

Fixes a bug in the new timeline code in which the limit query parameter wasn't always being fulfilled, in which case some clients like Tusky would then assume it didn't need to add a "load more" placeholder view even when there were more statuses to be loaded. This also fiddles around a bit in the logging middleware handler to add some more code comments, and add logging of full request URIs when it is safe to do so.

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4141
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-06 13:30:23 +00:00
kim
e464de1322 [bugfix] broken nootel function signatures (#4142)
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4142
Reviewed-by: Daenney <daenney@noreply.codeberg.org>
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-06 13:26:20 +00:00
tobi
cf93d3af0a [feature] Add description_limit to /api/v2/instance, increase default limit to 5k (#4140)
Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4131 by adding `description_limit` to the `api/v2/instance` response. Also increases default sizes to default status length to allow people to more easily describe things like screenshots of text.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4140
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-06 09:58:47 +00:00
nopjmp
57fc267b5c [feature] add ability to change s3 bucket lookup type (#4120)
# Description

This pull request implements the ability to specify the S3 bucket lookup type that is passed to the minio-go library. By default, minio-go uses a regex on the endpoint to see if it is a host that supports DNS access or not. Tigris and others are moving away from path style bucket access to DNS style bucket access using subdomains.

This keeps the default as 'auto' to allow existing users to not need to modify their configurations.

closes #3942

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4120
Reviewed-by: kim <gruf@noreply.codeberg.org>
Co-authored-by: nopjmp <nop@unearthly.dev>
Co-committed-by: nopjmp <nop@unearthly.dev>
2025-05-06 09:54:50 +00:00
Daenney
90a5425fe9 [chore] Add Go runtime and host metrics (#4137)
Daenney is a dummy and forgot to add these when he revamped the OTEL stuff.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4137
Co-authored-by: Daenney <daenney@noreply.codeberg.org>
Co-committed-by: Daenney <daenney@noreply.codeberg.org>
2025-05-06 08:18:05 +00:00
tobi
4a6b357501 [bugfix] Fixes to tablist, fileinput, checkbox (#4139)
Some fixes to various frontend things:

- Fix signup checkbox being height 0 on webkit - closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4136
- Fix wonky file input on chrome and webkit - closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4138
- Make tablist in interaction policies keyboard accessible with proper left/right + focus handling, see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/tablist_role

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4139
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-06 08:06:52 +00:00
tobi
73aa62581e [chore] fix testrig with new otel setup (#4135)
Follow-up to https://codeberg.org/superseriousbusiness/gotosocial/pulls/4110

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4135
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-05 17:28:01 +00:00
Daenney
ecbdc4227b [chore] Simplify the OTEL setup (#4110)
# Description

This simplifies our OTEL setup by:

* Getting rid of some deprecated things.
* Using `autoexport` and letting things get configured by the `OTEL_` environment variables.
* Removing all the unnecessary config options.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4110
Reviewed-by: tobi <kipvandenbos@noreply.codeberg.org>
Co-authored-by: Daenney <daenney@noreply.codeberg.org>
Co-committed-by: Daenney <daenney@noreply.codeberg.org>
2025-05-05 16:22:45 +00:00
tobi
ad71066973 [chore] Update goreleaser (#4133)
Updates gotosocial-woodpecker-build to a version that includes goreleaser v2.9.0, which should work properly with "gitea" aka forgejo (ie., codeberg).

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4133
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-05 14:18:21 +00:00
daenney
83184da6e7 [chore/github] Add an end of mirror notice (#4128)
# Description

Adds a small notice to the Github README with when we intend to stop mirroring.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4128
Co-authored-by: daenney <daenney@noreply.codeberg.org>
Co-committed-by: daenney <daenney@noreply.codeberg.org>
2025-05-05 12:44:28 +00:00
tobi
89df9f3b21 [bugfix] Prevent multiple mentions being created for one mention (#4127)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

This pull request fixes an issue where multiple mentions were being created for one statuses, when delivered to multiple inboxes on an instance, but only the final mention ended up actually being used. Also adds tests to make sure that a notification is received when a status is edited to include a mention.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4127
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-05 09:22:03 +00:00
tobi
f3f1854359 [bugfix] Fix no notification if mention edited into status (#4102)
This pull request adds mention notifications if a mention was edited into a status after its initial publication.

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/3869

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4102
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-04 09:45:10 +00:00
tobi
056c67f396 [chore/cicd] Account for force pushes in conditional runs (#4121)
CI_PIPELINE_FILES seems to be empty on force pushes to an open pull request, so this PR just accounts for that and runs all steps if it's the case, as we can't tell then what's actually changed.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4121
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-04 07:58:17 +00:00
kim
211192c482 [chore] more NoLLaMas proof-of-work tweaking (#4096)
- replaces the sha256 calculation with an alternative implementation that seems to use more uniform time-taken across different platforms
- goes back to the simpler difficulty calculation without a "partial" difficulty level

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4096
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-05-03 16:45:25 +00:00
tobi
c15002d76e [bugfix] Ensure Account and TargetAccount set when doing UndoFollow (#4118)
Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4112 by ensuring that Account and TargetAccount are properly set on the follow passed through to UndoFollow.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4118
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-03 10:10:23 +00:00
cdn0x12
bad427e7f0 [chore/docs] fix relative link to scraper deterrence (#4111)
# Description

While working on the doc translation update, I found a broken link. So I;m opening this separate PR to keep it clean from the translation stuff. Marked as draft currently for checking for any other typos :)

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4111
Co-authored-by: cdn0x12 <git@cdn0x12.dev>
Co-committed-by: cdn0x12 <git@cdn0x12.dev>
2025-05-03 09:28:43 +00:00
cdn0x12
4d6408015b [docs/zh] Update zh docs: synced to 6c879186 (#4117)
# Description

This PR updates the Chinese documentation to 6c879186 (the latest commit at present).

It also fixed a small typo in the original docs. Since the change is so minor, I didn't make a separate PR.

Last docs/zh update PR: #3884

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4117
Co-authored-by: cdn0x12 <git@cdn0x12.dev>
Co-committed-by: cdn0x12 <git@cdn0x12.dev>
2025-05-03 09:28:16 +00:00
tobi
6c87918635 [chore/cicd] Snapshot only if source code files have changed (#4115)
See https://codeberg.org/superseriousbusiness/gotosocial/issues/4113, follow up to https://codeberg.org/superseriousbusiness/gotosocial/pulls/4114

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4115
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-02 20:35:49 +00:00
tobi
bf10ca0203 [chore/cicd] conditional tests + linting for pull requests (#4114)
Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4113

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4114
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-02 20:26:09 +00:00
tobi
1480f22aea [bugfix/chore] Invalidate prepared statuses when account representation changes (#4107)
This pull requests adds logic to invalidate prepared statuses when an account's representation changes due to an update.

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4104

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4107
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-05-02 16:01:30 +00:00
tobi
1bad36b637 [bugfix] Fix wrong URI used in dereferenceLocal (#4097)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

Previously we were passing a *followers* URI into the federatingDB `Followers` function, which expects an *account* URI. This led to a nil body when doing internal dereferences (ie., while sending out messages). I think I probably wrote this bug when I refactored stuff a while ago.

This PR fixes that up by making the dereferenceLocal function more consistent, and falling back to an http dereference if nothing found. Clarifies behavior of the federatingdb.Get function as well, by commenting the shit out of it.

Also adds tests, precious tests.

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4066

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4097
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-04-30 18:19:01 +00:00
tobi
90f5004db0 [chore] Update release CICD to point at "gitea" (#4100)
Updates our release flow to point at "gitea", which should work for Codeberg as well.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4100
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-04-30 12:10:09 +00:00
tobi
ac01652de9 [bugfix] Fix migration unsetting bot flag (#4098)
Fixes an issue in the migration where bot actor type was being incorrectly set to Person.

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4086

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4098
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-04-30 11:17:20 +00:00
tobi
ef0f8a55c6 [bugfix] Fix nil ptr exception on creating user without running server first (#4094)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

closes https://codeberg.org/superseriousbusiness/gotosocial/issues/4049 by removing the silly defer statement. Adds a test too, and a warning in the docs.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4094
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-04-29 16:40:36 +00:00
kim
31628019fe [chore] tweak NoLLaMas proof-of-work algorithm (#4090)
# Description

- tweaks the NoLLaMas proof-of-work algorithm to further granularity on time spent computing solutions
- standardizes GoToSocial cookie security directive setting in a CookiePolicy{} type

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4090
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-04-29 13:57:26 +00:00
kim
14f15b321b [bugfix] don't prevent moved accounts from invalidating their old tokens (#4091)
# Description

Removes the move check from the invalidate token API handler, as moved accounts should be able to delete their old tokens.

closes #4067

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4091
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-04-29 13:43:01 +00:00
tobi
4fe5dfae56 [chore] nollamas: show tick + time taken on completion, use window.location.replace (#4088)
# Description

> If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements.
>
> If this is a documentation change, please briefly describe what you've changed and why.

Tweak to show time taken when solving nollamas, and use a pulser rather than a spinner to indicate work being done.

Also use `window.location.replace` for doing the redirect instead of setting window.location.href: https://developer.mozilla.org/en-US/docs/Web/API/Location/replace

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4088
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-04-29 10:49:10 +00:00
kim
efc79528d2 [docs] small changes to the proof-of-work scraper deterrence docs (#4084)
- moves it to the advanced section
- adds it to the mkdocs config
- adds warning about it not covering RSS endpoints

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4084
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-04-29 08:59:28 +00:00
kim
d8c4d9fc5a [feature] proof of work scraper deterrence (#4043)
This adds a proof-of-work based scraper deterrence to GoToSocial's middleware stack on profile and status web pages. Heavily inspired by https://github.com/TecharoHQ/anubis, but massively stripped back for our own usecase.

Todo:
- ~~add configuration option so this is disabled by default~~
- ~~fix whatever weirdness is preventing this working with CSP (even in debug)~~
- ~~use our standard templating mechanism going through apiutil helper func~~
- ~~probably some absurdly small performance improvements to be made in pooling re-used hex encode / hash encode buffers~~ the web endpoints aren't as hot a path as API / ActivityPub, will leave as-is for now as it is already very minimal and well optimized
- ~~verify the cryptographic assumptions re: using a portion of token as challenge data~~ this isn't a serious application of cryptography, if it turns out to be a problem we'll fix it, but it definitely should not be easily possible to guess a SHA256 hash from the first 1/4 of it even if mathematically it might make it a bit easier
- ~~theme / make look nice??~~
- ~~add a spinner~~
- ~~add entry in example configuration~~
- ~~add documentation~~

Verification page originally based on https://github.com/LucienV1/powtect

Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4043
Reviewed-by: tobi <tsmethurst@noreply.codeberg.org>
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-04-28 20:12:27 +00:00
Nicole Mikołajczyk
2b82fa7481 [chore/docs] add symmetry to the politics (#4081)
Signed-off-by: Nicole Mikołajczyk <git@mkljczk.pl>

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [ ] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4081
Co-authored-by: Nicole Mikołajczyk <git@mkljczk.pl>
Co-committed-by: Nicole Mikołajczyk <git@mkljczk.pl>
2025-04-28 18:20:09 +00:00
tobi
2d91eed4ed [chore] Remove unused import (#4077)
Remove an unused import that was causing the testrig not to build properly.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4077
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-04-28 14:19:58 +00:00
tobi
4c8ff7d1b2 [chore/docs] Put some politics in the code (#4076)
The code didn't have enough politics so this fixes that.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4076
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-04-28 13:28:59 +00:00
tobi
afb4279d27 [docs] Move docs links to codeberg (#4074)
Update more links from github -> codeberg in the docs.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4074
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-04-28 12:08:51 +00:00
kim
436765a6a2 bump dependencies: minio-go, go-sqlite3, goldmark, otel, x/image/webp (#4075)
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4075
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
2025-04-28 11:20:24 +00:00
tobi
457ca3c9d3 [chore] Update build to use new woodpecker dind container, bump version numbers (#4073)
As described!

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4073
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-04-28 09:31:51 +00:00
tobi
7dae3364fa [chore] Override woodpecker plugin for snapshot + release to get tags (#4069)
We need tags to do snapshots + releases properly! Another cheeky little difference from drone.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4069
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-04-27 22:07:59 +00:00
tobi
8bc0b06105 [chore] Fix CI/CD snapshot / release (#4068)
🤦

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4068
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-04-27 21:33:39 +00:00
İ. Göktuğ Kayaalp
d3e9a9e563 [docs] clearer structure for "combining blocks and allows" section (#4065)
# Description

This patch moves figures around in `admin/federation_modes.md` in order to make the text more approachable. Reading it, I found that I dwelled long on the chart, not thinking that there would be an easier to read explanation below, so I thought it'd make sense to swap the places. I also felt like the warning at the bottom was important enough that it'd better be up near the top of the section, highlighting the importance of understanding the explanation below.

I did not see a commit message style guide in project docs so I improvised based on recent commit messages

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [X] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [X] I/we have not leveraged AI to create the proposed changes.
- [ ] I/we have performed a self-review of added code.
- [ ] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [ ] I/we have run tests and they pass locally with the changes.
- [ ] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4065
Co-authored-by: İ. Göktuğ Kayaalp <self@gkayaalp.com>
Co-committed-by: İ. Göktuğ Kayaalp <self@gkayaalp.com>
2025-04-27 20:27:23 +00:00
daenney
d5c3f44bb9 [chore] Disable default issue template 2025-04-27 13:55:11 +00:00
Daenney
9b92175239 [chore] Bring back the issue and PR templates 2025-04-27 14:57:17 +02:00
Daenney
93c3c153f0 [chore] Rewrite all remaining Github links 2025-04-27 13:40:22 +02:00
tobi
5bfccdad3c [chore] add woodpecker ci/cd pipelines (#4061)
Removes our now unused drone stuff and adds pipelines for our new woodpecker instance.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4061
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-04-27 11:22:35 +00:00
Daenney
346962beb5 [chore] Fix daenney being bad at sed (#4060)
Co-authored-by: Daenney <daenney@users.noreply.github.com>
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4060
Co-authored-by: Daenney <daenney@noreply.codeberg.org>
Co-committed-by: Daenney <daenney@noreply.codeberg.org>
2025-04-26 19:19:52 +00:00
Daenney
ab10266bff [feature] Move to code.superseriousbusiness.org 2025-04-26 15:38:43 +02:00
Daenney
152bcb43b6 [chore] Set up Github to be a mirror 2025-04-26 15:38:43 +02:00
tobi
85eb192669
[chore] fix testrig build (#4059) 2025-04-26 15:24:15 +02:00
tobi
f7323c065a
[feature] Update attachment format, receive + send focalPoint prop + use it on the frontend (#4052)
* [feature] Update attachment format, receive + send `focalPoint` prop + use it on the frontend

* whoops

* boop

* restore function signature of ExtractAttachments
2025-04-26 15:03:05 +02:00
kim
6a6a499333
[performance] rewrite timelines to rely on new timeline cache type (#3941)
* start work rewriting timeline cache type

* further work rewriting timeline caching

* more work integration new timeline code

* remove old code

* add local timeline, fix up merge conflicts

* remove old use of go-bytes

* implement new timeline code into more areas of codebase, pull in latest go-mangler, go-mutexes, go-structr

* remove old timeline package, add local timeline cache

* remove references to old timeline types that needed starting up in tests

* start adding page validation

* fix test-identified timeline cache package issues

* fix up more tests, fix missing required changes, etc

* add exclusion for test.out in gitignore

* clarify some things better in code comments

* tweak cache size limits

* fix list timeline cache fetching

* further list timeline fixes

* linter, ssssssssshhhhhhhhhhhh please

* fix linter hints

* reslice the output if it's beyond length of 'lim'

* remove old timeline initialization code, bump go-structr to v0.9.4

* continued from previous commit

* improved code comments

* don't allow multiple entries for BoostOfID values to prevent repeated boosts of same boosts

* finish writing more code comments

* some variable renaming, for ease of following

* change the way we update lo,hi paging values during timeline load

* improved code comments for updated / returned lo , hi paging values

* finish writing code comments for the StatusTimeline{} type itself

* fill in more code comments

* update go-structr version to latest with changed timeline unique indexing logic

* have a local and public timeline *per user*

* rewrite calls to public / local timeline calls

* remove the zero length check, as lo, hi values might still be set

* simplify timeline cache loading, fix lo/hi returns, fix timeline invalidation side-effects missing for some federated actions

* swap the lo, hi values 🤦

* add (now) missing slice reverse of tag timeline statuses when paging ASC

* remove local / public caches (is out of scope for this work), share more timeline code

* remove unnecessary change

* again, remove more unused code

* remove unused function to appease the linter

* move boost checking to prepare function

* fix use of timeline.lastOrder, fix incorrect range functions used

* remove comments for repeat code

* remove the boost logic from prepare function

* do a maximum of 5 loads, not 10

* add repeat boost filtering logic, update go-structr, general improvements

* more code comments

* add important note

* fix timeline tests now that timelines are returned in page order

* remove unused field

* add StatusTimeline{} tests

* add more status timeline tests

* start adding preloading support

* ensure repeat boosts are marked in preloaded entries

* share a bunch of the database load code in timeline cache, don't clear timelines on relationship change

* add logic to allow dynamic clear / preloading of timelines

* comment-out unused functions, but leave in place as we might end-up using them

* fix timeline preload state check

* much improved status timeline code comments

* more code comments, don't bother inserting statuses if timeline not preloaded

* shift around some logic to make sure things aren't accidentally left set

* finish writing code comments

* remove trim-after-insert behaviour

* fix-up some comments referring to old logic

* remove unsetting of lo, hi

* fix preload repeatBoost checking logic

* don't return on status filter errors, these are usually transient

* better concurrency safety in Clear() and Done()

* fix test broken due to addition of preloader

* fix repeatBoost logic that doesn't account for already-hidden repeatBoosts

* ensure edit submodels are dropped on cache insertion

* update code-comment to expand CAS accronym

* use a plus1hULID() instead of 24h

* remove unused functions

* add note that public / local timeline requester can be nil

* fix incorrect visibility filtering of tag timeline statuses

* ensure we filter home timeline statuses on local only

* some small re-orderings to confirm query params in correct places

* fix the local only home timeline filter func
2025-04-26 09:56:15 +00:00
tobi
ffde1b150f
[chore] Move deps to code.superseriousbusiness.org (#4054) 2025-04-25 15:15:36 +02:00
tobi
68ed7aba25
[chore] Update activity to v1.14.0 (#4038) 2025-04-24 11:20:03 +02:00
Ember
768ee70b88
[docs] Mention where to run the command to grant CREATE permissions (#4050) 2025-04-24 11:00:20 +02:00
2402 changed files with 398323 additions and 151979 deletions

2
.github/README.md vendored
View file

@ -1,3 +1,5 @@
# GoToSocial
This is a mirror. You can find us on https://codeberg.org/superseriousbusiness/gotosocial.
We will **stop mirroring** to Github after 0.20 is released. This will likely be sometime **in August**.

7
.gitignore vendored
View file

@ -4,6 +4,10 @@
# exclude built documentation, since readthedocs will build it for us anyway
/docs/_build
# exclude kim's commonly used
# test stdout file location
test.out
# exclude coverage report
cp.out
@ -19,6 +23,9 @@ dist/
# exclude the copy of swagger.yaml moved into assets during packaging
web/assets/swagger.yaml
# exclude the copy of all_licenses.txt moved into assets during packaging
web/assets/all_licenses.txt
# exludes docker-volume from exemple/docker-compose
example/docker-compose/docker-volume

View file

@ -4,91 +4,98 @@
#
# For GoToSocial we mostly take the default linters, but we add a few to catch style issues as well.
version: "2"
# options for analysis running
run:
# include test files or not, default is true
tests: false
# timeout for analysis, e.g. 30s, 5m, default is 1m
timeout: 5m
linters:
# enable some extra linters, see here for the list: https://golangci-lint.run/usage/linters/
enable:
- gocritic
- gofmt
- goheader
- gosec
- nilerr
- revive
# https://golangci-lint.run/usage/linters/#linters-configuration
settings:
# https://golangci-lint.run/usage/linters/#goheader
goheader:
template: |-
GoToSocial
Copyright (C) GoToSocial Authors admin@gotosocial.org
SPDX-License-Identifier: AGPL-3.0-or-later
# https://golangci-lint.run/usage/linters/#linters-configuration
linters-settings:
# https://golangci-lint.run/usage/linters/#goheader
goheader:
template: |-
GoToSocial
Copyright (C) GoToSocial Authors admin@gotosocial.org
SPDX-License-Identifier: AGPL-3.0-or-later
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
# https://golangci-lint.run/usage/linters/#govet
govet:
disable:
- composites
# https://golangci-lint.run/usage/linters/#revive
revive:
rules:
# Enable most default rules.
# See: https://github.com/mgechev/revive/blob/master/defaults.toml
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: error-naming
- name: error-return
- name: error-strings
- name: exported
- name: if-return
- name: increment-decrement
- name: var-naming
- name: var-declaration
- name: package-comments
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: empty-block
- name: superfluous-else
- name: unreachable-code
# Disable below rules.
- name: redefines-builtin-id
disabled: true # This one is just annoying.
- name: unused-parameter
disabled: true # We often pass parameters to fulfil interfaces.
# https://golangci-lint.run/usage/linters/#staticcheck
staticcheck:
# Enable all checks, but disable SA1012: nil context passing.
# See: https://staticcheck.io/docs/configuration/options/#checks
checks: ["all", "-SA1012"]
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
# https://golangci-lint.run/usage/linters/#govet
govet:
disable:
- composites
# https://golangci-lint.run/usage/linters/#revive
revive:
rules:
# Enable most default rules.
# See: https://github.com/mgechev/revive/blob/master/defaults.toml
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: error-naming
- name: error-return
- name: error-strings
- name: exported
- name: if-return
- name: increment-decrement
- name: var-naming
- name: var-declaration
- name: package-comments
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: empty-block
- name: superfluous-else
- name: unreachable-code
# Disable below rules.
- name: redefines-builtin-id
disabled: true
- name: unused-parameter
disabled: true
- name: var-naming
arguments:
- []
- []
- - skip-package-name-checks: true
issues:
exclude-rules:
# Exclude VSCode custom folding region comments in files that use them.
# Already fixed in go-critic and can be removed next time go-critic is updated.
- linters:
- gocritic
path: internal/db/filter.go
text: 'commentFormatting: put a space between `//` and comment text'
# https://golangci-lint.run/usage/linters/#staticcheck
staticcheck:
# Enable all checks, but disable SA1012: nil context passing.
# See: https://staticcheck.io/docs/configuration/options/#checks
checks:
- SA*
- -SA1012
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
formatters:
enable:
- gofmt
exclusions:
generated: lax

View file

@ -17,6 +17,8 @@ before:
- yarn --cwd ./web/source install
- yarn --cwd ./web/source ts-patch install # https://typia.io/docs/setup/#manual-setup
- yarn --cwd ./web/source build
# Bundle all licenses into web/assets/all_licenses.txt
- ./scripts/bundle_licenses.sh
# https://goreleaser.com/customization/build/
builds:

View file

@ -16,16 +16,13 @@ steps:
# https://woodpecker-ci.org/docs/usage/environment#built-in-environment-variables
- evaluate: >-
(not ("CI_PIPELINE_FILES" in $env)) ||
len(CI_PIPELINE_FILES) == 0 ||
any(fromJSON(CI_PIPELINE_FILES), {
# startsWith "internal/" ||
# startsWith "cmd/" ||
# startsWith "testrig/"
})
CI_PIPELINE_FILES == "[]" ||
any(fromJSON(CI_PIPELINE_FILES), { # startsWith "internal/" || # startsWith "cmd/" || # startsWith "testrig/" }) ||
len(fromJSON(CI_PIPELINE_FILES)) == 0
# We use golangci-lint for linting.
# See: https://golangci-lint.run/
image: golangci/golangci-lint:v1.62.0
image: golangci/golangci-lint:v2.3.1
pull: true
# https://woodpecker-ci.org/docs/administration/configuration/backends/docker#run-user
@ -60,15 +57,11 @@ steps:
# https://woodpecker-ci.org/docs/usage/environment#built-in-environment-variables
- evaluate: >-
(not ("CI_PIPELINE_FILES" in $env)) ||
len(CI_PIPELINE_FILES) == 0 ||
any(fromJSON(CI_PIPELINE_FILES), {
# startsWith "internal/" ||
# startsWith "cmd/" ||
# startsWith "testrig/" ||
# startsWith "vendor/"
})
CI_PIPELINE_FILES == "[]" ||
any(fromJSON(CI_PIPELINE_FILES), { # startsWith "internal/" || # startsWith "cmd/" || # startsWith "testrig/" || # startsWith "vendor/" }) ||
len(fromJSON(CI_PIPELINE_FILES)) == 0
image: golang:1.23-alpine
image: golang:1.24-alpine
pull: true
# https://woodpecker-ci.org/docs/administration/configuration/backends/docker#run-user
@ -99,9 +92,6 @@ steps:
./...
- ./test/envparsing.sh
- ./test/swagger.sh
# https://woodpecker-ci.org/docs/usage/workflow-syntax#depends_on
depends_on: [lint]
# Validate the web code only
# if web source has changed.
@ -116,8 +106,9 @@ steps:
# https://woodpecker-ci.org/docs/usage/environment#built-in-environment-variables
- evaluate: >-
(not ("CI_PIPELINE_FILES" in $env)) ||
len(CI_PIPELINE_FILES) == 0 ||
any(fromJSON(CI_PIPELINE_FILES), { # startsWith "web/source/" })
CI_PIPELINE_FILES == "[]" ||
any(fromJSON(CI_PIPELINE_FILES), { # startsWith "web/source/" }) ||
len(fromJSON(CI_PIPELINE_FILES)) == 0
image: node:lts-alpine
pull: true

View file

@ -13,7 +13,7 @@ clone:
steps:
release:
# https://codeberg.org/superseriousbusiness/gotosocial-woodpecker-build
image: superseriousbusiness/gotosocial-woodpecker-build:0.11.0
image: superseriousbusiness/gotosocial-woodpecker-build:0.12.1
pull: true
# https://woodpecker-ci.org/docs/usage/volumes

View file

@ -24,17 +24,12 @@ steps:
# https://woodpecker-ci.org/docs/usage/environment#built-in-environment-variables
- evaluate: >-
(not ("CI_PIPELINE_FILES" in $env)) ||
any(fromJSON(CI_PIPELINE_FILES), {
# startsWith "internal/" ||
# startsWith "cmd/" ||
# startsWith "testrig/" ||
# startsWith "vendor/" ||
# startsWith "web/" ||
# == "Dockerfile"
})
CI_PIPELINE_FILES == "[]" ||
any(fromJSON(CI_PIPELINE_FILES), { # startsWith "internal/" || # startsWith "cmd/" || # startsWith "testrig/" || # startsWith "vendor/" || # startsWith "web/" || # == "Dockerfile" }) ||
len(fromJSON(CI_PIPELINE_FILES)) == 0
# https://codeberg.org/superseriousbusiness/gotosocial-woodpecker-build
image: superseriousbusiness/gotosocial-woodpecker-build:0.11.0
image: superseriousbusiness/gotosocial-woodpecker-build:0.12.1
pull: true
# https://woodpecker-ci.org/docs/usage/volumes

View file

@ -18,20 +18,23 @@ These contribution guidelines were adapted from / inspired by those of Gitea (ht
- [Docker](#docker)
- [With GoReleaser](#with-goreleaser)
- [Manually](#manually)
- [Stylesheet / Web dev](#stylesheet--web-dev)
- [Stylesheet / Web dev](#stylesheet-web-dev)
- [Live Reloading](#live-reloading)
- [Project Structure](#project-structure)
- [Finding your way around the code](#finding-your-way-around-the-code)
- [Style / Linting / Formatting](#style--linting--formatting)
- [Style / Linting / Formatting](#style-linting-formatting)
- [Testing](#testing)
- [Standalone Testrig with Pinafore](#standalone-testrig-with-pinafore)
- [Configuring the Standalone Testrig](#configuring-the-standalone-testrig)
- [Running automated tests](#running-automated-tests)
- [SQLite](#sqlite)
- [Postgres](#postgres)
- [CLI Tests](#cli-tests)
- [Federation](#federation)
- [Updating Swagger docs](#updating-swagger-docs)
- [CI/CD configuration](#cicd-configuration)
- [CI/CD configuration](#ci-cd-configuration)
- [Other Useful Stuff](#other-useful-stuff)
- [Running migrations on a Postgres DB backup locally](#running-migrations-on-a-postgres-db-backup-locally)
## Introduction
@ -182,7 +185,7 @@ Normally, these processes are handled by Drone (see CI/CD above). However, you c
To do this, first [install GoReleaser](https://goreleaser.com/install/).
Then install Node and Yarn as described in [Stylesheet / Web dev](#stylesheet--web-dev).
Then install Node and Yarn as described in [Stylesheet / Web dev](#stylesheet-web-dev).
Finally, to create a snapshot build, do:
@ -422,10 +425,35 @@ At the login screen, enter the email address `zork@example.org` and password `pa
Note the following constraints:
- Since the testrig uses an in-memory database, the database will be destroyed when the testrig is stopped.
- If you stop the testrig and start it again, any tokens or applications you created during your tests will also be removed. As such, you need to log out and in again every time you stop/start the rig.
- Since the testrig uses an in-memory database by default, the database will be destroyed when the testrig is stopped.
- If you stop the testrig and start it again, by default any tokens or applications you created during your tests will also be removed. As such, you need to log out and in again every time you stop/start the rig.
- The testrig does not make any actual external HTTP calls, so federation will not work from a testrig.
##### Configuring the Standalone Testrig
By default the standalone testrig uses an in-memory SQLite database, which is filled with test data when starting up, and is cleared when shutting down, but you can tweak this (and a few other settings) with environment variables:
- `GTS_LOG_LEVEL` - you can set this to `trace` if you want to see all DB queries.
- `GTS_TESTRIG_SKIP_DB_SETUP` - set this to any value to skip the creation of tables and population of test data when the testrig starts.
- `GTS_TESTRIG_SKIP_DB_TEARDOWN` - set this to any value to skip the deletion of tables and test data when the testrig stops.
- `GTS_STORAGE_BACKEND` - this uses in-memory storage by default, but you can set this to `s3` to use a locally-running Minio etc for testing.
- `GTS_DB_TYPE` - you can change this to `postgres` to test against a locally-running Postgres intance.
- `GTS_DB_ADDRESS` - this is set to `:memory:` by default. You can change this to use an sqlite.db file somewhere, or set it to a Postgres address.
- `GTS_DB_PORT`, `GTS_DB_USER`, `GTS_DB_PASSWORD`, `GTS_DB_DATABASE`, `GTS_DB_TLS_MODE`, `GTS_DB_TLS_CA_CERT` - you can set these if you change `GTS_DB_ADDRESS` to `postgres` and don't use `GTS_DB_POSTGRES_CONNECTION_STRING`.
- `GTS_DB_POSTGRES_CONNECTION_STRING` - use this to provide a Postgres connection string if you don't want to set all the db env variables mentioned in the previous point.
Using these variables you can also (albeit awkwardly) test migrations from one schema to another.
For example, to test SQLite migrations:
1. Switch to main branch.
2. Build the debug binary, and then start the testrig with `DEBUG=1 GTS_LOG_LEVEL=trace GTS_DB_ADDRESS=./sqlite.test.db GTS_TESTRIG_SKIP_DB_TEARDOWN=1 ./gotosocial testrig start`. This instructs the testrig to use trace logging, use an actual file for the SQLite db, and to skip tearing it down when finished.
3. Stop the testrig.
4. The file `sqlite.test.db` now contains the schema and test models from the main branch.
5. Switch to the branch with the migration you want to test.
6. Build the debug binary, and then start the testrig with `DEBUG=1 GTS_LOG_LEVEL=trace GTS_DB_ADDRESS=./sqlite.test.db GTS_TESTRIG_SKIP_DB_SETUP=1 ./gotosocial testrig start`. This instructs the testrig to use trace logging, and to use the already-populated sqlite.test.db file.
7. You should see logging for migrations.
#### Running automated tests
Tests can be run against both SQLite and Postgres.
@ -499,3 +527,38 @@ The `woodpecker` pipeline files are in the `.woodpecker` directory of this repos
The Woodpecker instance for GoToSocial is [here](https://woodpecker.superseriousbusiness.org/repos/2).
Documentation for Woodpecker is [here](https://woodpecker-ci.org/docs/intro).
## Other Useful Stuff
Various bits and bobs.
### Running migrations on a Postgres DB backup locally
It may be useful when testing or debugging migrations to be able to run them against a copy of a real instance's Postgres database locally.
Basic steps for this:
First dump the Postgres database on the remote machine, and copy the dump over to your development machine.
Now create a local Postgres container and mount the dump into it with, for example:
```bash
docker run -it --name postgres --network host -e POSTGRES_PASSWORD=postgres -v /path/to/db_dump:/db_dump postgres
```
In a separate terminal window, execute a command inside the running container to load the dump into the "postgres" database:
```bash
docker exec -it --user postgres postgres psql -X -f /db_dump postgres
```
With the Postgres container still running, run GoToSocial and point it towards the container. Use the appropriate `GTS_HOST` (and `GTS_ACCOUNT_DOMAIN`) values for the instance you dumped:
```bash
GTS_HOST=example.org \
GTS_DB_TYPE=postgres \
GTS_DB_POSTGRES_CONNECTION_STRING=postgres://postgres:postgres@localhost:5432/postgres \
./gotosocial migrations run
```
When you're done messing around, don't forget to remove any containers that you started up, and remove any lingering volumes with `docker volume prune`, else you might end up filling your disk with unused temporary volumes.

View file

@ -36,7 +36,7 @@ Here's a screenshot of the instance landing page! Check out the project's [offic
- [Rich text formatting](#rich-text-formatting)
- [Themes and custom CSS](#themes-and-custom-css)
- [Easy to run](#easy-to-run)
- [Safety + security features](#safety--security-features)
- [Safety + security features](#safety-security-features)
- [Various federation modes](#various-federation-modes)
- [OIDC integration](#oidc-integration)
- [Backend-first design](#backend-first-design)
@ -51,7 +51,7 @@ Here's a screenshot of the instance landing page! Check out the project's [offic
- [Stable Releases](#stable-releases)
- [Snapshot Releases](#snapshot-releases)
- [Docker](#docker)
- [Binary release .tar.gz](#binary-release-targz)
- [Binary release .tar.gz](#binary-release-tar-gz)
- [From Source](#from-source)
- [Third-party Packaging](#third-party-packaging)
- [Contributing](#contributing)
@ -61,7 +61,7 @@ Here's a screenshot of the instance landing page! Check out the project's [offic
- [Image Attribution and Licensing](#image-attribution-and-licensing)
- [Team](#team)
- [Special Thanks](#special-thanks)
- [Sponsorship + Funding](#sponsorship--funding)
- [Sponsorship + Funding](#sponsorship-funding)
- [Crowdfunding](#crowdfunding)
- [Corporate Sponsorship](#corporate-sponsorship)
- [NLnet](#nlnet)
@ -134,7 +134,7 @@ GoToSocial lets you choose who can reply to your posts, via [interaction policie
### Local-only posting
Sometimes you only want to talk to people you share an instance with. GoToSocial supports this via local-only posting, which ensures that your post stays on your instance only. (Local-only posting is currently dependent on client support.)
Sometimes you only want to talk to people you share an instance with. GoToSocial supports this via local-only posting, which ensures that your post stays on your instance only, even if it gets boosted. They also do not show up in the web interface, and are not accessible publicly via URL. (Local-only posting is currently dependent on client support.)
### RSS feed
@ -213,6 +213,26 @@ It's also easy for admins to [add their own custom themes](https://docs.gotosoci
<figcaption>Sunset</figcaption>
</figure>
<hr/>
<figure>
<img src="https://codeberg.org/superseriousbusiness/gotosocial/raw/branch/main/docs/overrides/public/theme-hacker-dark.png"/>
<figcaption>Hacker dark</figcaption>
</figure>
<hr/>
<figure>
<img src="https://codeberg.org/superseriousbusiness/gotosocial/raw/branch/main/docs/overrides/public/theme-hacker-light.png"/>
<figcaption>Hacker light</figcaption>
</figure>
<hr/>
<figure>
<img src="https://codeberg.org/superseriousbusiness/gotosocial/raw/branch/main/docs/overrides/public/theme-programmer-socks-dark.png"/>
<figcaption>Programmer socks dark</figcaption>
</figure>
<hr/>
<figure>
<img src="https://codeberg.org/superseriousbusiness/gotosocial/raw/branch/main/docs/overrides/public/theme-programmer-socks-light.png"/>
<figcaption>Programmer socks light</figcaption>
</figure>
<hr/>
</details>
### Easy to run
@ -272,9 +292,9 @@ Don't like GtS but still want to use the fediverse? Like GtS but prefer not to u
## Known Issues
Since GoToSocial is still in beta, there are plenty of bugs. We use [Codeberg issues](https://codeberg.org/superseriousbusiness/gotosocial/issues?q=is%3Aissue+is%3Aopen+label%3Abug) to track these.
Since GoToSocial is still in beta, there are plenty of bugs. We use [Codeberg issues](https://codeberg.org/superseriousbusiness/gotosocial/issues?labels=378161) to track these.
Since every ActivityPub server implementation has a slightly different interpretation of the protocol, some servers don't quite federate properly with GoToSocial yet. We're tracking these issues [in this project](https://codeberg.org/superseriousbusiness/gotosocial/projects/4). Eventually, we want to make sure that any implementation that can federate nicely with Mastodon should also be able to federate with GoToSocial.
Since every ActivityPub server implementation has a slightly different interpretation of the protocol, some servers don't quite federate properly with GoToSocial yet. We're tracking these issues [with the federation label](https://codeberg.org/superseriousbusiness/gotosocial/issues?labels=378188). Eventually, we want to make sure that any implementation that can federate nicely with Mastodon should also be able to federate with GoToSocial.
---
@ -308,7 +328,7 @@ This is the current status of support offered by GoToSocial for different platfo
Notes on 64-bit CPU feature requirements:
- x86_64 requires the SSE4.1 instruction set. (CPUs manufactured after ~2010)
- x86_64 requires the [x86-64-v2](https://en.wikipedia.org/wiki/X86-64-v2) level instruction sets. (CPUs manufactured after ~2010)
- ARM64 requires no specific features, ARMv8 CPUs (and later) have all required features.
@ -424,6 +444,7 @@ The following open source libraries, frameworks, and tools are used by GoToSocia
- [gruf/go-mutexes](https://codeberg.org/gruf/go-mutexes); safemutex & mutex map. [MIT License](https://spdx.org/licenses/MIT.html).
- [gruf/go-runners](https://codeberg.org/gruf/go-runners); synchronization utilities. [MIT License](https://spdx.org/licenses/MIT.html).
- [gruf/go-sched](https://codeberg.org/gruf/go-sched); task scheduler. [MIT License](https://spdx.org/licenses/MIT.html).
- [gruf/go-split](https://codeberg.org/gruf/go-split); configuration string handling. [MIT License](https://spdx.org/licenses/MIT.html).
- [gruf/go-storage](https://codeberg.org/gruf/go-storage); file storage backend (local & s3). [MIT License](https://spdx.org/licenses/MIT.html).
- [gruf/go-structr](https://codeberg.org/gruf/go-structr); struct caching + queueing with automated indexing by field. [MIT License](https://spdx.org/licenses/MIT.html).
- jackc:

View file

@ -13,10 +13,10 @@ Big thank you to all of our [Open Collective](https://opencollective.com/gotosoc
- [Beta Aims](#beta-aims)
- [Timeline](#timeline)
- [Mid 2023](#mid-2023)
- [Mid/late 2023](#midlate-2023)
- [Mid/late 2023](#mid-late-2023)
- [Early 2024](#early-2024)
- [BETA milestone](#beta-milestone)
- [Remainder 2024 - early 2025](#remainder-2024---early-2025)
- [Remainder 2024 - early 2025](#remainder-2024-early-2025)
- [On the way out of BETA to STABLE RELEASE](#on-the-way-out-of-beta-to-stable-release)
- [Wishlist](#wishlist)

View file

@ -87,8 +87,8 @@ Thirdly, we want to make GtS as customizable as possible by allowing admins to e
The main technical challenges we foresee on the project are:
1. Ensuring compatibility with other AP servers (see here: https://codeberg.org/superseriousbusiness/gotosocial/projects/4).
2. Ensuring compatibility with clients that use the Mastodon API (see here: https://codeberg.org/superseriousbusiness/gotosocial/projects/5).
1. Ensuring compatibility with other AP servers (see federation issues: https://codeberg.org/superseriousbusiness/gotosocial/issues?labels=378188).
2. Ensuring compatibility with clients that use the Mastodon API (see client compatibility issues: https://codeberg.org/superseriousbusiness/gotosocial/issues?labels=378194).
3. Designing nuanced federation safety features that allow instance admins to screen federation without totally breaking it. This will require careful design discussions and lots of testing.
4. Implementing our own open-source http signature library with a reference implementation of the latest draft of the http signature proposal: https://httpwg.org/http-extensions/draft-ietf-httpbis-message-signatures.html.
5. Writing + maintaining our own extensions to the AP protocol (see below).

View file

@ -83,8 +83,8 @@ Thirdly, we want to make GtS as customizable as possible by allowing admins to e
The main technical challenges we foresee on the project are:
1. Ensuring compatibility with other AP servers (see here: https://codeberg.org/superseriousbusiness/gotosocial/projects/4).
2. Ensuring compatibility with clients that use the Mastodon API (see here: https://codeberg.org/superseriousbusiness/gotosocial/projects/5).
1. Ensuring compatibility with other AP servers (see federation issues: https://codeberg.org/superseriousbusiness/gotosocial/issues?labels=378188).
2. Ensuring compatibility with clients that use the Mastodon API (see client compatibility issues: https://codeberg.org/superseriousbusiness/gotosocial/issues?labels=378194).
3. Designing nuanced federation safety features that allow instance admins to screen federation without totally breaking it. This will require careful design discussions and lots of testing.
4. Implementing our own open-source http signature library with a reference implementation of the latest draft of the http signature proposal: https://httpwg.org/http-extensions/draft-ietf-httpbis-message-signatures.html.
5. Writing + maintaining our own extensions to the AP protocol (see below).

View file

@ -29,12 +29,25 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/db/bundb"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/log"
userprocessor "code.superseriousbusiness.org/gotosocial/internal/processing/user"
"code.superseriousbusiness.org/gotosocial/internal/state"
"code.superseriousbusiness.org/gotosocial/internal/util"
"code.superseriousbusiness.org/gotosocial/internal/validate"
"golang.org/x/crypto/bcrypt"
)
var (
// check function conformance
_ action.GTSAction = Create
_ action.GTSAction = List
_ action.GTSAction = Confirm
_ action.GTSAction = Promote
_ action.GTSAction = Demote
_ action.GTSAction = Enable
_ action.GTSAction = Disable
_ action.GTSAction = Password
)
func initState(ctx context.Context) (*state.State, error) {
var state state.State
state.Caches.Init()
@ -61,7 +74,7 @@ func stopState(state *state.State) error {
// Create creates a new account and user
// in the database using the provided flags.
var Create action.GTSAction = func(ctx context.Context) error {
func Create(ctx context.Context) error {
state, err := initState(ctx)
if err != nil {
return err
@ -118,7 +131,7 @@ var Create action.GTSAction = func(ctx context.Context) error {
}
// List returns all existing local accounts.
var List action.GTSAction = func(ctx context.Context) error {
func List(ctx context.Context) error {
state, err := initState(ctx)
if err != nil {
return err
@ -156,7 +169,7 @@ var List action.GTSAction = func(ctx context.Context) error {
// Confirm sets a user to Approved, sets Email to the current
// UnconfirmedEmail value, and sets ConfirmedAt to now.
var Confirm action.GTSAction = func(ctx context.Context) error {
func Confirm(ctx context.Context) error {
state, err := initState(ctx)
if err != nil {
return err
@ -198,7 +211,7 @@ var Confirm action.GTSAction = func(ctx context.Context) error {
}
// Promote sets admin + moderator flags on a user to true.
var Promote action.GTSAction = func(ctx context.Context) error {
func Promote(ctx context.Context) error {
state, err := initState(ctx)
if err != nil {
return err
@ -235,7 +248,7 @@ var Promote action.GTSAction = func(ctx context.Context) error {
}
// Demote sets admin + moderator flags on a user to false.
var Demote action.GTSAction = func(ctx context.Context) error {
func Demote(ctx context.Context) error {
state, err := initState(ctx)
if err != nil {
return err
@ -272,7 +285,7 @@ var Demote action.GTSAction = func(ctx context.Context) error {
}
// Disable sets Disabled to true on a user.
var Disable action.GTSAction = func(ctx context.Context) error {
func Disable(ctx context.Context) error {
state, err := initState(ctx)
if err != nil {
return err
@ -308,7 +321,7 @@ var Disable action.GTSAction = func(ctx context.Context) error {
}
// Enable sets Disabled to false on a user.
var Enable action.GTSAction = func(ctx context.Context) error {
func Enable(ctx context.Context) error {
state, err := initState(ctx)
if err != nil {
return err
@ -344,7 +357,7 @@ var Enable action.GTSAction = func(ctx context.Context) error {
}
// Password sets the password of target account.
var Password action.GTSAction = func(ctx context.Context) error {
func Password(ctx context.Context) error {
state, err := initState(ctx)
if err != nil {
return err
@ -389,3 +402,41 @@ var Password action.GTSAction = func(ctx context.Context) error {
"encrypted_password",
)
}
// Disable2FA disables 2FA for target account.
func Disable2FA(ctx context.Context) error {
state, err := initState(ctx)
if err != nil {
return err
}
defer func() {
// Ensure state gets stopped on return.
if err := stopState(state); err != nil {
log.Error(ctx, err)
}
}()
username := config.GetAdminAccountUsername()
if err := validate.Username(username); err != nil {
return err
}
account, err := state.DB.GetAccountByUsernameDomain(ctx, username, "")
if err != nil {
return err
}
user, err := state.DB.GetUserByAccountID(ctx, account.ID)
if err != nil {
return err
}
err = userprocessor.TwoFactorDisable(ctx, state, user)
if err != nil {
return err
}
fmt.Printf("2fa disabled\n")
return nil
}

View file

@ -18,12 +18,10 @@
package media
import (
"bufio"
"context"
"errors"
"fmt"
"os"
"path"
"code.superseriousbusiness.org/gotosocial/cmd/gotosocial/action"
"code.superseriousbusiness.org/gotosocial/internal/config"
@ -33,80 +31,168 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/log"
"code.superseriousbusiness.org/gotosocial/internal/paging"
"code.superseriousbusiness.org/gotosocial/internal/state"
"codeberg.org/gruf/go-byteutil"
"codeberg.org/gruf/go-fastpath/v2"
)
// check function conformance.
var _ action.GTSAction = ListAttachments
var _ action.GTSAction = ListEmojis
// ListAttachments lists local, remote, or all attachment paths.
func ListAttachments(ctx context.Context) error {
list, err := setupList(ctx)
if err != nil {
return err
}
defer func() {
// Ensure lister gets shutdown on exit.
if err := list.shutdown(); err != nil {
log.Errorf(ctx, "error shutting down: %v", err)
}
}()
// List attachment media paths from db.
return list.ListAttachmentPaths(ctx)
}
// ListEmojis lists local, remote, or all emoji filepaths.
func ListEmojis(ctx context.Context) error {
list, err := setupList(ctx)
if err != nil {
return err
}
defer func() {
// Ensure lister gets shutdown on exit.
if err := list.shutdown(); err != nil {
log.Errorf(ctx, "error shutting down: %v", err)
}
}()
// List emoji media paths from db.
return list.ListEmojiPaths(ctx)
}
type list struct {
dbService db.DB
state *state.State
page paging.Page
localOnly bool
remoteOnly bool
out *bufio.Writer
}
// Get a list of attachment using a custom filter
func (l *list) GetAllAttachmentPaths(ctx context.Context, filter func(*gtsmodel.MediaAttachment) string) ([]string, error) {
res := make([]string, 0, 100)
func (l *list) ListAttachmentPaths(ctx context.Context) error {
// Page reused for iterative
// attachment queries, with
// predefined limit.
var page paging.Page
page.Limit = 500
// Storage base path, used for path building.
basePath := config.GetStorageLocalBasePath()
for {
// Get the next page of media attachments up to max ID.
attachments, err := l.dbService.GetAttachments(ctx, &l.page)
// Get next page of media attachments up to max ID.
medias, err := l.state.DB.GetAttachments(ctx, &page)
if err != nil && !errors.Is(err, db.ErrNoEntries) {
return nil, fmt.Errorf("failed to retrieve media metadata from database: %w", err)
return fmt.Errorf("failed to fetch media from database: %w", err)
}
// Get current max ID.
maxID := l.page.Max.Value
maxID := page.Max.Value
// If no attachments or the same group is returned, we reached the end.
if len(attachments) == 0 || maxID == attachments[len(attachments)-1].ID {
// If no media or the same group is returned, we reached end.
if len(medias) == 0 || maxID == medias[len(medias)-1].ID {
break
}
// Use last ID as the next 'maxID' value.
maxID = attachments[len(attachments)-1].ID
l.page.Max = paging.MaxID(maxID)
// Use last ID as the next 'maxID'.
maxID = medias[len(medias)-1].ID
page.Max.Value = maxID
for _, a := range attachments {
v := filter(a)
if v != "" {
res = append(res, v)
switch {
case l.localOnly:
// Only print local media paths.
for _, media := range medias {
if media.RemoteURL == "" {
printMediaPaths(basePath, media)
}
}
case l.remoteOnly:
// Only print remote media paths.
for _, media := range medias {
if media.RemoteURL != "" {
printMediaPaths(basePath, media)
}
}
default:
// Print all known media paths.
for _, media := range medias {
printMediaPaths(basePath, media)
}
}
}
return res, nil
return nil
}
// Get a list of emojis using a custom filter
func (l *list) GetAllEmojisPaths(ctx context.Context, filter func(*gtsmodel.Emoji) string) ([]string, error) {
res := make([]string, 0, 100)
func (l *list) ListEmojiPaths(ctx context.Context) error {
// Page reused for iterative
// attachment queries, with
// predefined limit.
var page paging.Page
page.Limit = 500
// Storage base path, used for path building.
basePath := config.GetStorageLocalBasePath()
for {
// Get the next page of emoji media up to max ID.
attachments, err := l.dbService.GetEmojis(ctx, &l.page)
emojis, err := l.state.DB.GetEmojis(ctx, &page)
if err != nil && !errors.Is(err, db.ErrNoEntries) {
return nil, fmt.Errorf("failed to retrieve media metadata from database: %w", err)
return fmt.Errorf("failed to fetch emojis from database: %w", err)
}
// Get current max ID.
maxID := l.page.Max.Value
maxID := page.Max.Value
// If no attachments or the same group is returned, we reached the end.
if len(attachments) == 0 || maxID == attachments[len(attachments)-1].ID {
// If no emojis or the same group is returned, we reached end.
if len(emojis) == 0 || maxID == emojis[len(emojis)-1].ID {
break
}
// Use last ID as the next 'maxID' value.
maxID = attachments[len(attachments)-1].ID
l.page.Max = paging.MaxID(maxID)
// Use last ID as the next 'maxID'.
maxID = emojis[len(emojis)-1].ID
page.Max.Value = maxID
for _, a := range attachments {
v := filter(a)
if v != "" {
res = append(res, v)
switch {
case l.localOnly:
// Only print local emoji paths.
for _, emoji := range emojis {
if emoji.ImageRemoteURL == "" {
printEmojiPaths(basePath, emoji)
}
}
case l.remoteOnly:
// Only print remote emoji paths.
for _, emoji := range emojis {
if emoji.ImageRemoteURL != "" {
printEmojiPaths(basePath, emoji)
}
}
default:
// Print all known emoji paths.
for _, emoji := range emojis {
printEmojiPaths(basePath, emoji)
}
}
}
return res, nil
return nil
}
func setupList(ctx context.Context) (*list, error) {
@ -124,150 +210,84 @@ func setupList(ctx context.Context) (*list, error) {
)
}
// Initialize caches.
state.Caches.Init()
// Ensure background cache tasks are running.
if err := state.Caches.Start(); err != nil {
return nil, fmt.Errorf("error starting caches: %w", err)
}
var err error
// Only set state DB connection.
// Don't need Actions or Workers for this.
dbService, err := bundb.NewBunDBService(ctx, &state)
state.DB, err = bundb.NewBunDBService(ctx, &state)
if err != nil {
return nil, fmt.Errorf("error creating dbservice: %w", err)
}
state.DB = dbService
return &list{
dbService: dbService,
state: &state,
page: paging.Page{Limit: 200},
localOnly: localOnly,
remoteOnly: remoteOnly,
out: bufio.NewWriter(os.Stdout),
}, nil
}
func (l *list) shutdown() error {
l.out.Flush()
err := l.dbService.Close()
err := l.state.DB.Close()
l.state.Caches.Stop()
return err
}
// ListAttachments lists local, remote, or all attachment paths.
var ListAttachments action.GTSAction = func(ctx context.Context) error {
list, err := setupList(ctx)
if err != nil {
return err
// reusable path building buffer,
// only usable here as we're not
// performing concurrent writes.
var pb fastpath.Builder
// reusable string output buffer,
// only usable here as we're not
// performing concurrent writes.
var outbuf byteutil.Buffer
func printMediaPaths(basePath string, media *gtsmodel.MediaAttachment) {
// Append file path if present.
if media.File.Path != "" {
path := pb.Join(basePath, media.File.Path)
_, _ = outbuf.WriteString(path + "\n")
}
defer func() {
// Ensure lister gets shutdown on exit.
if err := list.shutdown(); err != nil {
log.Error(ctx, err)
}
}()
var (
mediaPath = config.GetStorageLocalBasePath()
filter func(*gtsmodel.MediaAttachment) string
)
switch {
case list.localOnly:
filter = func(m *gtsmodel.MediaAttachment) string {
if m.RemoteURL != "" {
// Remote, not
// interested.
return ""
}
return path.Join(mediaPath, m.File.Path)
}
case list.remoteOnly:
filter = func(m *gtsmodel.MediaAttachment) string {
if m.RemoteURL == "" {
// Local, not
// interested.
return ""
}
return path.Join(mediaPath, m.File.Path)
}
default:
filter = func(m *gtsmodel.MediaAttachment) string {
return path.Join(mediaPath, m.File.Path)
}
// Append thumb path if present.
if media.Thumbnail.Path != "" {
path := pb.Join(basePath, media.Thumbnail.Path)
_, _ = outbuf.WriteString(path + "\n")
}
attachments, err := list.GetAllAttachmentPaths(ctx, filter)
if err != nil {
return err
// Only write if any
// string was prepared.
if outbuf.Len() > 0 {
_, _ = os.Stdout.Write(outbuf.B)
outbuf.Reset()
}
for _, a := range attachments {
_, _ = list.out.WriteString(a + "\n")
}
return nil
}
// ListEmojis lists local, remote, or all emoji filepaths.
var ListEmojis action.GTSAction = func(ctx context.Context) error {
list, err := setupList(ctx)
if err != nil {
return err
func printEmojiPaths(basePath string, emoji *gtsmodel.Emoji) {
// Append image path if present.
if emoji.ImagePath != "" {
path := pb.Join(basePath, emoji.ImagePath)
_, _ = outbuf.WriteString(path + "\n")
}
defer func() {
// Ensure lister gets shutdown on exit.
if err := list.shutdown(); err != nil {
log.Error(ctx, err)
}
}()
var (
mediaPath = config.GetStorageLocalBasePath()
filter func(*gtsmodel.Emoji) string
)
switch {
case list.localOnly:
filter = func(e *gtsmodel.Emoji) string {
if e.ImageRemoteURL != "" {
// Remote, not
// interested.
return ""
}
return path.Join(mediaPath, e.ImagePath)
}
case list.remoteOnly:
filter = func(e *gtsmodel.Emoji) string {
if e.ImageRemoteURL == "" {
// Local, not
// interested.
return ""
}
return path.Join(mediaPath, e.ImagePath)
}
default:
filter = func(e *gtsmodel.Emoji) string {
return path.Join(mediaPath, e.ImagePath)
}
// Append static path if present.
if emoji.ImageStaticPath != "" {
path := pb.Join(basePath, emoji.ImageStaticPath)
_, _ = outbuf.WriteString(path + "\n")
}
emojis, err := list.GetAllEmojisPaths(ctx, filter)
if err != nil {
return err
// Only write if any
// string was prepared.
if outbuf.Len() > 0 {
_, _ = os.Stdout.Write(outbuf.B)
outbuf.Reset()
}
for _, e := range emojis {
_, _ = list.out.WriteString(e + "\n")
}
return nil
}

View file

@ -26,8 +26,11 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/log"
)
// check function conformance.
var _ action.GTSAction = All
// All performs all media clean actions
var All action.GTSAction = func(ctx context.Context) error {
func All(ctx context.Context) error {
// Setup pruning utilities.
prune, err := setupPrune(ctx)
if err != nil {

View file

@ -26,8 +26,11 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/log"
)
// check function conformance.
var _ action.GTSAction = Orphaned
// Orphaned prunes orphaned media from storage.
var Orphaned action.GTSAction = func(ctx context.Context) error {
func Orphaned(ctx context.Context) error {
// Setup pruning utilities.
prune, err := setupPrune(ctx)
if err != nil {

View file

@ -27,8 +27,11 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/log"
)
// check function conformance.
var _ action.GTSAction = Remote
// Remote prunes old and/or unused remote media.
var Remote action.GTSAction = func(ctx context.Context) error {
func Remote(ctx context.Context) error {
// Setup pruning utilities.
prune, err := setupPrune(ctx)
if err != nil {

View file

@ -29,8 +29,11 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/trans"
)
// check function conformance.
var _ action.GTSAction = Export
// Export exports info from the database into a file
var Export action.GTSAction = func(ctx context.Context) error {
func Export(ctx context.Context) error {
var state state.State
// Only set state DB connection.

View file

@ -29,8 +29,11 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/trans"
)
// check function conformance.
var _ action.GTSAction = Import
// Import imports info from a file into the database
var Import action.GTSAction = func(ctx context.Context) error {
func Import(ctx context.Context) error {
var state state.State
// Only set state DB connection.

View file

@ -26,17 +26,17 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/config"
)
// check function conformance.
var _ action.GTSAction = Config
// Config just prints the collated config out to stdout as json.
var Config action.GTSAction = func(ctx context.Context) (err error) {
func Config(ctx context.Context) (err error) {
var raw map[string]interface{}
// Marshal configuration to a raw JSON map
config.Config(func(cfg *config.Configuration) {
raw, err = cfg.MarshalMap()
raw = cfg.MarshalMap()
})
if err != nil {
return err
}
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")

View file

@ -0,0 +1,68 @@
// GoToSocial
// Copyright (C) GoToSocial Authors admin@gotosocial.org
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package migration
import (
"context"
"fmt"
"code.superseriousbusiness.org/gotosocial/cmd/gotosocial/action"
"code.superseriousbusiness.org/gotosocial/internal/db/bundb"
"code.superseriousbusiness.org/gotosocial/internal/log"
"code.superseriousbusiness.org/gotosocial/internal/state"
)
// check function conformance.
var _ action.GTSAction = Run
// Run will initialize the database, running any available migrations.
func Run(ctx context.Context) error {
var state state.State
defer func() {
if state.DB != nil {
// Lastly, if database service was started,
// ensure it gets closed now all else stopped.
if err := state.DB.Close(); err != nil {
log.Errorf(ctx, "error stopping database: %v", err)
}
}
// Finally reached end of shutdown.
log.Info(ctx, "done! exiting...")
}()
// Initialize caches
state.Caches.Init()
if err := state.Caches.Start(); err != nil {
return fmt.Errorf("error starting caches: %w", err)
}
log.Info(ctx, "starting db service...")
// Open connection to the database now caches started.
dbService, err := bundb.NewBunDBService(ctx, &state)
if err != nil {
return fmt.Errorf("error creating dbservice: %s", err)
}
// Set DB on state.
state.DB = dbService
return nil
}

View file

@ -41,7 +41,9 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/federation"
"code.superseriousbusiness.org/gotosocial/internal/federation/federatingdb"
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
"code.superseriousbusiness.org/gotosocial/internal/filter/spam"
"code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
"code.superseriousbusiness.org/gotosocial/internal/httpclient"
@ -55,12 +57,10 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/observability"
"code.superseriousbusiness.org/gotosocial/internal/oidc"
"code.superseriousbusiness.org/gotosocial/internal/processing"
tlprocessor "code.superseriousbusiness.org/gotosocial/internal/processing/timeline"
"code.superseriousbusiness.org/gotosocial/internal/router"
"code.superseriousbusiness.org/gotosocial/internal/state"
gtsstorage "code.superseriousbusiness.org/gotosocial/internal/storage"
"code.superseriousbusiness.org/gotosocial/internal/subscriptions"
"code.superseriousbusiness.org/gotosocial/internal/timeline"
"code.superseriousbusiness.org/gotosocial/internal/transport"
"code.superseriousbusiness.org/gotosocial/internal/typeutils"
"code.superseriousbusiness.org/gotosocial/internal/web"
@ -70,9 +70,13 @@ import (
"go.uber.org/automaxprocs/maxprocs"
)
// check function conformance.
var _ action.GTSAction = Maintenance
var _ action.GTSAction = Start
// Maintenance starts and creates a GoToSocial server
// in maintenance mode (returns 503 for most requests).
var Maintenance action.GTSAction = func(ctx context.Context) error {
func Maintenance(ctx context.Context) error {
route, err := router.New(ctx)
if err != nil {
return fmt.Errorf("error creating maintenance router: %w", err)
@ -101,7 +105,7 @@ var Maintenance action.GTSAction = func(ctx context.Context) error {
}
// Start creates and starts a gotosocial server
var Start action.GTSAction = func(ctx context.Context) error {
func Start(ctx context.Context) error {
// Set GOMAXPROCS / GOMEMLIMIT
// to match container limits.
setLimits(ctx)
@ -139,20 +143,6 @@ var Start action.GTSAction = func(ctx context.Context) error {
// Noop on unstarted workers.
state.Workers.Stop()
if state.Timelines.Home != nil {
// Home timeline mgr was setup, ensure it gets stopped.
if err := state.Timelines.Home.Stop(); err != nil {
log.Errorf(ctx, "error stopping home timeline: %v", err)
}
}
if state.Timelines.List != nil {
// List timeline mgr was setup, ensure it gets stopped.
if err := state.Timelines.List.Stop(); err != nil {
log.Errorf(ctx, "error stopping list timeline: %v", err)
}
}
if process != nil {
const timeout = time.Minute
@ -200,7 +190,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
}
// Initialize tracing (noop if not enabled).
if err := observability.InitializeTracing(); err != nil {
if err := observability.InitializeTracing(ctx); err != nil {
return fmt.Errorf("error initializing tracing: %w", err)
}
@ -284,10 +274,12 @@ var Start action.GTSAction = func(ctx context.Context) error {
)
typeConverter := typeutils.NewConverter(state)
visFilter := visibility.NewFilter(state)
muteFilter := mutes.NewFilter(state)
intFilter := interaction.NewFilter(state)
statusFilter := status.NewFilter(state)
spamFilter := spam.NewFilter(state)
federatingDB := federatingdb.New(state, typeConverter, visFilter, intFilter, spamFilter)
transportController := transport.NewController(state, federatingDB, &federation.Clock{}, client)
transportController := transport.NewController(state, federatingDB, client)
federator := federation.NewFederator(
state,
federatingDB,
@ -323,26 +315,6 @@ var Start action.GTSAction = func(ctx context.Context) error {
// Create a Web Push notification sender.
webPushSender := webpush.NewSender(client, state, typeConverter)
// Initialize both home / list timelines.
state.Timelines.Home = timeline.NewManager(
tlprocessor.HomeTimelineGrab(state),
tlprocessor.HomeTimelineFilter(state, visFilter),
tlprocessor.HomeTimelineStatusPrepare(state, typeConverter),
tlprocessor.SkipInsert(),
)
if err := state.Timelines.Home.Start(); err != nil {
return fmt.Errorf("error starting home timeline: %s", err)
}
state.Timelines.List = timeline.NewManager(
tlprocessor.ListTimelineGrab(state),
tlprocessor.ListTimelineFilter(state, visFilter),
tlprocessor.ListTimelineStatusPrepare(state, typeConverter),
tlprocessor.SkipInsert(),
)
if err := state.Timelines.List.Start(); err != nil {
return fmt.Errorf("error starting list timeline: %s", err)
}
// Start the job scheduler
// (this is required for cleaner).
state.Workers.StartScheduler()
@ -384,7 +356,9 @@ var Start action.GTSAction = func(ctx context.Context) error {
emailSender,
webPushSender,
visFilter,
muteFilter,
intFilter,
statusFilter,
)
// Schedule background cleaning tasks.
@ -412,8 +386,13 @@ var Start action.GTSAction = func(ctx context.Context) error {
return fmt.Errorf("error scheduling poll expiries: %w", err)
}
// schedule publication tasks for all scheduled statuses.
if err := process.Status().ScheduledStatusesScheduleAll(ctx); err != nil {
return fmt.Errorf("error scheduling status publications: %w", err)
}
// Initialize metrics.
if err := observability.InitializeMetrics(state.DB); err != nil {
if err := observability.InitializeMetrics(ctx, state); err != nil {
return fmt.Errorf("error initializing metrics: %w", err)
}
@ -514,17 +493,19 @@ var Start action.GTSAction = func(ctx context.Context) error {
return fmt.Errorf("error generating session name for session middleware: %w", err)
}
// Configure our instance cookie policy.
cookiePolicy := apiutil.NewCookiePolicy()
var (
authModule = api.NewAuth(state, process, idp, routerSession, sessionName) // auth/oauth paths
clientModule = api.NewClient(state, process) // api client endpoints
metricsModule = api.NewMetrics() // Metrics endpoints
healthModule = api.NewHealth(dbService.Ready) // Health check endpoints
fileserverModule = api.NewFileserver(process) // fileserver endpoints
robotsModule = api.NewRobots() // robots.txt endpoint
wellKnownModule = api.NewWellKnown(process) // .well-known endpoints
nodeInfoModule = api.NewNodeInfo(process) // nodeinfo endpoint
activityPubModule = api.NewActivityPub(dbService, process) // ActivityPub endpoints
webModule = web.New(dbService, process) // web pages + user profiles + settings panels etc
authModule = api.NewAuth(state, process, idp, routerSession, sessionName, cookiePolicy) // auth/oauth paths
clientModule = api.NewClient(state, process) // api client endpoints
healthModule = api.NewHealth(dbService.Ready) // Health check endpoints
fileserverModule = api.NewFileserver(process) // fileserver endpoints
robotsModule = api.NewRobots() // robots.txt endpoint
wellKnownModule = api.NewWellKnown(process) // .well-known endpoints
nodeInfoModule = api.NewNodeInfo(process) // nodeinfo endpoint
activityPubModule = api.NewActivityPub(dbService, process) // ActivityPub endpoints
webModule = web.New(dbService, process, cookiePolicy) // web pages + user profiles + settings panels etc
)
// Create per-route / per-grouping middlewares.
@ -571,7 +552,6 @@ var Start action.GTSAction = func(ctx context.Context) error {
// apply throttling *after* rate limiting
authModule.Route(route, clLimit, clThrottle, robotsDisallowAll, gzip)
clientModule.Route(route, clLimit, clThrottle, robotsDisallowAll, gzip)
metricsModule.Route(route, clLimit, clThrottle, robotsDisallowAIOnly)
healthModule.Route(route, clLimit, clThrottle, robotsDisallowAIOnly)
fileserverModule.Route(route, fsMainLimit, fsThrottle, robotsDisallowAIOnly)
fileserverModule.RouteEmojis(route, instanceAccount.ID, fsEmojiLimit, fsThrottle, robotsDisallowAIOnly)
@ -652,14 +632,14 @@ func parseClientRanges() (
allowIPs := config.GetHTTPClientAllowIPs()
allowRanges := make([]netip.Prefix, len(allowIPs))
allowFlag := config.HTTPClientAllowIPsFlag()
allowFlag := config.HTTPClientAllowIPsFlag
if err := parseF(allowIPs, allowRanges, allowFlag); err != nil {
return nil, err
}
blockIPs := config.GetHTTPClientBlockIPs()
blockRanges := make([]netip.Prefix, len(blockIPs))
blockFlag := config.HTTPClientBlockIPsFlag()
blockFlag := config.HTTPClientBlockIPsFlag
if err := parseF(blockIPs, blockRanges, blockFlag); err != nil {
return nil, err
}

View file

@ -19,8 +19,15 @@
package testrig
import "code.superseriousbusiness.org/gotosocial/cmd/gotosocial/action"
import (
"context"
"code.superseriousbusiness.org/gotosocial/cmd/gotosocial/action"
)
// check function conformance.
var _ action.GTSAction = Start
// Start creates and starts a gotosocial testrig server.
// This is only enabled in debug builds, else is nil.
var Start action.GTSAction
func Start(context.Context) error { return nil }

View file

@ -34,28 +34,28 @@ import (
apiutil "code.superseriousbusiness.org/gotosocial/internal/api/util"
"code.superseriousbusiness.org/gotosocial/internal/cleaner"
"code.superseriousbusiness.org/gotosocial/internal/config"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
"code.superseriousbusiness.org/gotosocial/internal/language"
"code.superseriousbusiness.org/gotosocial/internal/log"
"code.superseriousbusiness.org/gotosocial/internal/middleware"
"code.superseriousbusiness.org/gotosocial/internal/observability"
"code.superseriousbusiness.org/gotosocial/internal/oidc"
tlprocessor "code.superseriousbusiness.org/gotosocial/internal/processing/timeline"
"code.superseriousbusiness.org/gotosocial/internal/router"
"code.superseriousbusiness.org/gotosocial/internal/state"
"code.superseriousbusiness.org/gotosocial/internal/storage"
"code.superseriousbusiness.org/gotosocial/internal/subscriptions"
"code.superseriousbusiness.org/gotosocial/internal/timeline"
"code.superseriousbusiness.org/gotosocial/internal/typeutils"
"code.superseriousbusiness.org/gotosocial/internal/web"
"code.superseriousbusiness.org/gotosocial/testrig"
"github.com/gin-gonic/gin"
)
// check function conformance.
var _ action.GTSAction = Start
// Start creates and starts a gotosocial testrig server.
// This is only enabled in debug builds, else is nil.
var Start action.GTSAction = func(ctx context.Context) error {
func Start(ctx context.Context) error {
testrig.InitTestConfig()
testrig.InitTestLog()
@ -89,29 +89,20 @@ var Start action.GTSAction = func(ctx context.Context) error {
// tasks from being executed.
testrig.StopWorkers(state)
if state.Timelines.Home != nil {
// Home timeline mgr was setup, ensure it gets stopped.
if err := state.Timelines.Home.Stop(); err != nil {
log.Errorf(ctx, "error stopping home timeline: %v", err)
}
}
if state.Timelines.List != nil {
// List timeline mgr was setup, ensure it gets stopped.
if err := state.Timelines.List.Stop(); err != nil {
log.Errorf(ctx, "error stopping list timeline: %v", err)
}
}
if state.Storage != nil {
// If storage was created, ensure torn down.
testrig.StandardStorageTeardown(state.Storage)
}
if state.DB != nil {
// Clean up database by
// dropping tables if required.
if !config.GetTestrigSkipDBTeardown() {
testrig.StandardDBTeardown(state.DB)
}
// Lastly, if database service was started,
// ensure it gets closed now all else stopped.
testrig.StandardDBTeardown(state.DB)
if err := state.DB.Close(); err != nil {
log.Errorf(ctx, "error stopping database: %v", err)
}
@ -127,7 +118,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
}
config.SetInstanceLanguages(parsedLangs)
if err := observability.InitializeTracing(); err != nil {
if err := observability.InitializeTracing(ctx); err != nil {
return fmt.Errorf("error initializing tracing: %w", err)
}
@ -142,7 +133,10 @@ var Start action.GTSAction = func(ctx context.Context) error {
// that twice, we can just start the initialized caches.
state.Caches.Start()
testrig.StandardDBSetup(state.DB, nil)
// Populate database tables + data if required.
if !config.GetTestrigSkipDBSetup() {
testrig.StandardDBSetup(state.DB, nil)
}
// Get the instance account (we'll need this later).
instanceAccount, err := state.DB.GetInstanceAccount(ctx, "")
@ -170,27 +164,6 @@ var Start action.GTSAction = func(ctx context.Context) error {
emailSender := testrig.NewEmailSender("./web/template/", nil)
webPushSender := testrig.NewWebPushMockSender()
typeConverter := typeutils.NewConverter(state)
filter := visibility.NewFilter(state)
// Initialize both home / list timelines.
state.Timelines.Home = timeline.NewManager(
tlprocessor.HomeTimelineGrab(state),
tlprocessor.HomeTimelineFilter(state, filter),
tlprocessor.HomeTimelineStatusPrepare(state, typeConverter),
tlprocessor.SkipInsert(),
)
if err := state.Timelines.Home.Start(); err != nil {
return fmt.Errorf("error starting home timeline: %s", err)
}
state.Timelines.List = timeline.NewManager(
tlprocessor.ListTimelineGrab(state),
tlprocessor.ListTimelineFilter(state, filter),
tlprocessor.ListTimelineStatusPrepare(state, typeConverter),
tlprocessor.SkipInsert(),
)
if err := state.Timelines.List.Start(); err != nil {
return fmt.Errorf("error starting list timeline: %s", err)
}
processor := testrig.NewTestProcessor(state, federator, emailSender, webPushSender, mediaManager)
@ -199,7 +172,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
defer testrig.StopWorkers(state)
// Initialize metrics.
if err := observability.InitializeMetrics(state.DB); err != nil {
if err := observability.InitializeMetrics(ctx, state); err != nil {
return fmt.Errorf("error initializing metrics: %w", err)
}
@ -282,23 +255,24 @@ var Start action.GTSAction = func(ctx context.Context) error {
return fmt.Errorf("error generating session name for session middleware: %w", err)
}
// Configure our instance cookie policy.
cookiePolicy := apiutil.NewCookiePolicy()
var (
authModule = api.NewAuth(state, processor, idp, routerSession, sessionName) // auth/oauth paths
clientModule = api.NewClient(state, processor) // api client endpoints
metricsModule = api.NewMetrics() // Metrics endpoints
healthModule = api.NewHealth(state.DB.Ready) // Health check endpoints
fileserverModule = api.NewFileserver(processor) // fileserver endpoints
robotsModule = api.NewRobots() // robots.txt endpoint
wellKnownModule = api.NewWellKnown(processor) // .well-known endpoints
nodeInfoModule = api.NewNodeInfo(processor) // nodeinfo endpoint
activityPubModule = api.NewActivityPub(state.DB, processor) // ActivityPub endpoints
webModule = web.New(state.DB, processor) // web pages + user profiles + settings panels etc
authModule = api.NewAuth(state, processor, idp, routerSession, sessionName, cookiePolicy) // auth/oauth paths
clientModule = api.NewClient(state, processor) // api client endpoints
healthModule = api.NewHealth(state.DB.Ready) // Health check endpoints
fileserverModule = api.NewFileserver(processor) // fileserver endpoints
robotsModule = api.NewRobots() // robots.txt endpoint
wellKnownModule = api.NewWellKnown(processor) // .well-known endpoints
nodeInfoModule = api.NewNodeInfo(processor) // nodeinfo endpoint
activityPubModule = api.NewActivityPub(state.DB, processor) // ActivityPub endpoints
webModule = web.New(state.DB, processor, cookiePolicy) // web pages + user profiles + settings panels etc
)
// these should be routed in order
authModule.Route(route)
clientModule.Route(route)
metricsModule.Route(route)
healthModule.Route(route)
fileserverModule.Route(route)
fileserverModule.RouteEmojis(route, instanceAccount.ID)

View file

@ -146,6 +146,19 @@ func adminCommands() *cobra.Command {
config.AddAdminAccountPassword(adminAccountPasswordCmd)
adminAccountCmd.AddCommand(adminAccountPasswordCmd)
adminAccountDisable2FACmd := &cobra.Command{
Use: "disable-2fa",
Short: "disable 2fa for the given local account",
PreRunE: func(cmd *cobra.Command, args []string) error {
return preRun(preRunArgs{cmd: cmd})
},
RunE: func(cmd *cobra.Command, args []string) error {
return run(cmd.Context(), account.Disable2FA)
},
}
config.AddAdminAccount(adminAccountDisable2FACmd)
adminAccountCmd.AddCommand(adminAccountDisable2FACmd)
adminCmd.AddCommand(adminAccountCmd)
/*

View file

@ -43,16 +43,16 @@ type preRunArgs struct {
// env vars or cli flag.
func preRun(a preRunArgs) error {
if err := config.BindFlags(a.cmd); err != nil {
return fmt.Errorf("error binding flags: %s", err)
return fmt.Errorf("error binding flags: %w", err)
}
if err := config.Reload(); err != nil {
return fmt.Errorf("error reloading config: %s", err)
if err := config.LoadConfigFile(); err != nil {
return fmt.Errorf("error loading config file: %w", err)
}
if !a.skipValidation {
if err := config.Validate(); err != nil {
return fmt.Errorf("invalid config: %s", err)
return fmt.Errorf("invalid config: %w", err)
}
}
@ -64,11 +64,17 @@ func preRun(a preRunArgs) error {
// context, after initializing any last-minute things like loggers etc.
func run(ctx context.Context, action action.GTSAction) error {
log.SetTimeFormat(config.GetLogTimestampFormat())
// Set the global log level from configuration
// Set the global log level from configuration.
if err := log.ParseLevel(config.GetLogLevel()); err != nil {
return fmt.Errorf("error parsing log level: %w", err)
}
// Set global log output format from configuration.
if err := log.ParseFormat(config.GetLogFormat()); err != nil {
return fmt.Errorf("error parsing log format: %w", err)
}
if config.GetSyslogEnabled() {
// Enable logging to syslog
if err := log.EnableSyslog(

View file

@ -19,7 +19,6 @@ package main
import (
configaction "code.superseriousbusiness.org/gotosocial/cmd/gotosocial/action/debug/config"
"code.superseriousbusiness.org/gotosocial/internal/config"
"github.com/spf13/cobra"
)
@ -39,7 +38,6 @@ func debugCommands() *cobra.Command {
return run(cmd.Context(), configaction.Config)
},
}
config.AddServerFlags(debugConfigCmd)
debugCmd.AddCommand(debugConfigCmd)
return debugCmd
}

View file

@ -23,10 +23,9 @@ import (
godebug "runtime/debug"
"strings"
"github.com/spf13/cobra"
_ "code.superseriousbusiness.org/gotosocial/docs"
"code.superseriousbusiness.org/gotosocial/internal/config"
"github.com/spf13/cobra"
)
// Version is the version of GoToSocial being used.
@ -41,27 +40,22 @@ func main() {
// override version in config store
config.SetSoftwareVersion(version)
// instantiate the root command
rootCmd := &cobra.Command{
Use: "gotosocial",
Short: "GoToSocial - a fediverse social media server",
Long: "GoToSocial - a fediverse social media server\n\nFor help, see: https://docs.gotosocial.org.\n\nCode: https://codeberg.org/superseriousbusiness/gotosocial",
Version: version,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// before running any other cmd funcs, we must load config-path
return config.LoadEarlyFlags(cmd)
},
SilenceErrors: true,
SilenceUsage: true,
}
rootCmd := new(cobra.Command)
rootCmd.Use = "gotosocial"
rootCmd.Short = "GoToSocial - a fediverse social media server"
rootCmd.Long = "GoToSocial - a fediverse social media server\n\nFor help, see: https://docs.gotosocial.org.\n\nCode: https://codeberg.org/superseriousbusiness/gotosocial"
rootCmd.Version = version
rootCmd.SilenceErrors = true
rootCmd.SilenceUsage = true
// attach global flags to the root command so that they can be accessed from any subcommand
config.AddGlobalFlags(rootCmd)
// Register global flags with root.
config.RegisterGlobalFlags(rootCmd)
// add subcommands
// Add subcommands with their flags.
rootCmd.AddCommand(serverCommands())
rootCmd.AddCommand(debugCommands())
rootCmd.AddCommand(adminCommands())
rootCmd.AddCommand(migrationCommands())
// Testrigcmd will only be set when debug is enabled.
if testrigCmd := testrigCommands(); testrigCmd != nil {
@ -70,7 +64,7 @@ func main() {
log.Fatal("gotosocial must be built and run with the DEBUG enviroment variable set to enable and access testrig")
}
// run
// Run the prepared root command.
if err := rootCmd.Execute(); err != nil {
log.Fatalf("error executing command: %s", err)
}

View file

@ -15,24 +15,29 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package v1
package main
import (
"context"
"fmt"
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/cmd/gotosocial/action/migration"
"github.com/spf13/cobra"
)
// apiFilter is a shortcut to return the API v1 filter version of the given
// filter keyword, or return an appropriate error if conversion fails.
func (p *Processor) apiFilter(ctx context.Context, filterKeyword *gtsmodel.FilterKeyword) (*apimodel.FilterV1, gtserror.WithCode) {
apiFilter, err := p.converter.FilterKeywordToAPIFilterV1(ctx, filterKeyword)
if err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting filter keyword to API v1 filter: %w", err))
// migrationCommands returns the 'migrations' subcommand
func migrationCommands() *cobra.Command {
migrationCmd := &cobra.Command{
Use: "migrations",
Short: "gotosocial migrations-related tasks",
}
return apiFilter, nil
migrationRunCmd := &cobra.Command{
Use: "run",
Short: "starts and stops the database, running any outstanding migrations",
PreRunE: func(cmd *cobra.Command, args []string) error {
return preRun(preRunArgs{cmd: cmd})
},
RunE: func(cmd *cobra.Command, args []string) error {
return run(cmd.Context(), migration.Run)
},
}
migrationCmd.AddCommand(migrationRunCmd)
return migrationCmd
}

View file

@ -19,7 +19,6 @@ package main
import (
"code.superseriousbusiness.org/gotosocial/cmd/gotosocial/action/server"
"code.superseriousbusiness.org/gotosocial/internal/config"
"github.com/spf13/cobra"
)
@ -39,7 +38,6 @@ func serverCommands() *cobra.Command {
return run(cmd.Context(), server.Start)
},
}
config.AddServerFlags(serverStartCmd)
serverCmd.AddCommand(serverStartCmd)
serverMaintenanceCmd := &cobra.Command{
@ -52,7 +50,6 @@ func serverCommands() *cobra.Command {
return run(cmd.Context(), server.Maintenance)
},
}
config.AddServerFlags(serverMaintenanceCmd)
serverCmd.AddCommand(serverMaintenanceCmd)
return serverCmd

View file

@ -19,11 +19,13 @@ package main
import (
"code.superseriousbusiness.org/gotosocial/cmd/gotosocial/action/testrig"
"code.superseriousbusiness.org/gotosocial/internal/config"
"codeberg.org/gruf/go-debug"
"github.com/spf13/cobra"
)
func testrigCommands() *cobra.Command {
if testrig.Start != nil {
if debug.DEBUG {
testrigCmd := &cobra.Command{
Use: "testrig",
Short: "gotosocial testrig-related tasks",
@ -38,6 +40,7 @@ func testrigCommands() *cobra.Command {
}
testrigCmd.AddCommand(testrigStartCmd)
config.AddTestrig(testrigCmd)
return testrigCmd
}
return nil

View file

@ -41,9 +41,9 @@ With this in mind, you should only ever treat domain blocking as *one layer* of
Unfortunately, the Fediverse has its share of trolls, many of whom see domain blocking as an adversary to be defeated. To achieve this, they often target instances which use domain blocks to protect users.
As such, there are bots on the Fediverse which scrape instance domain blocks and announce any discovered blocks to the followers of the bot, opening the admin of the blocking instance up to harassment. These bots use the `api/v1/instance/peers?filter=suspended` endpoint of GoToSocial instances to gather domain block information.
As such, there are bots on the Fediverse which scrape instance domain blocks and announce any discovered blocks to the followers of the bot, opening the admin of the blocking instance up to harassment. These bots use the `api/v1/instance/peers?filter=suspended`, `api/v1/instance/peers?filter=blocked`, and/or `api/v1/instance/domain_blocks` endpoints of GoToSocial instances to gather domain block information.
By default, GoToSocial does not expose this endpoint publicly, so your instance will be safe from such scraping. However, if you set `instance-expose-suspended` to `true` in your config.yaml file, you may find that this endpoint gets scraped occasionally, and you may see your blocks being announced by troll bots.
By default, GoToSocial does not expose these endpoints publicly, so your instance will be safe from such scraping. However, if you set `instance-expose-blocklist` to `true` in your config.yaml file, you may find that these endpoints gets scraped occasionally, and you may see your blocks being announced by troll bots.
## What are the side effects of creating a domain block

View file

@ -21,9 +21,28 @@ The subscription with the higher priority is the one that now creates and manage
If the subscription with the higher priority is removed, then the next time all the subscriptions are fetched, "Less Important List" will create (or take ownership of) the domain allow instead.
## Retractions
Sometimes, an entry that was present on a subscribed block or allow list will be removed later by the curator(s) of that list. When this happens, the removed domain permission entry can be said to have been "retracted".
For example, say your instance subscribes to one block list, and that block list contains an entry for `baddies.example.org`. A corresponding domain block for `baddies.example.org` has therefore been created in your database, with the subscription ID of your block list. In other words, the domain block is in force, and is managed by your block list subscription.
At some point, your instance fetches the list again, and this time it sees that the entry for `baddies.example.org` is no longer present in the list, because it has been removed by the list curator(s) (perhaps the admins turned their policies around, or the instance was shut down, etc). Thus, according to your instance, the block for `baddies.example.org` is now a "retracted" domain permission entry.
If the domain permission subscription is set to "Remove retracted permissions," then the now-retracted domain block will be removed from the database, and will no longer be enforced. In this example, that means your instance will start federating (again) with `baddies.example.org`.
If the domain permission subscription is *not* set to "Remove retracted permissions," then instead of the retracted block being removed from the database, it will be kept in the database but "orphaned" -- ie., it will still be in force, but it will be marked as no longer being managed by the subscription. In this example, that means your instance will keep blocking `baddies.example.org`.
!!!! Note "Retracted permissions and other subscriptions"
When a permission is retracted and removed from the database, but an entry for it exists on the list of *another* subscription of a lower priority than the one it was retracted from, then the permission will be recreated as an entry managed by the lower priority list.
For example, say you subscribe to List1 at priority 255, and List2 at priority 128, and `baddies.example.org` is present on both lists. That means the domain block entry will be managed by List1. If List1 later *retracts* the entry, it will be removed from your database (assuming you have "Remove retracted permissions" set). However, as soon as List2 is checked (usually seconds after List1), then an entry for `baddies.example.org` will be created again, but managed by List2 this time.
In other words, it is only when an entry is retracted from *every list you subscribe to* that it will truly be removed.
## Orphan Permissions
Domain permissions (blocks or allows) that are not currently managed by a domain permission subscription are considered "orphan" permissions. This includes permissions that an admin created in the settings panel by hand, or which were imported manually via the import/export page.
Domain permissions (blocks or allows) that are not currently managed by a domain permission subscription are considered "orphan" permissions. This includes permissions that an admin created in the settings panel by hand, entries which were imported manually via the import/export page, or entries that belonged to a subscription but have since been retracted but not removed.
If you wish, when creating a domain permission subscription, you can set ["adopt orphans"](./settings.md#adopt-orphan-permissions) to true for that subscription. If a domain permission subscription that is set to adopt orphans encounters an orphan permission which is *also present on the list at the subscription's URI*, then it will "adopt" the orphan by setting the orphan's subscription ID to its own ID.

View file

@ -10,8 +10,6 @@ You can allow or disallow crawlers from collecting stats about your instance fro
The AI scrapers come from a [community maintained repository][airobots]. It's manually kept in sync for the time being. If you know of any missing robots, please send them a PR!
A number of AI scrapers are known to ignore entries in `robots.txt` even if it explicitly matches their User-Agent. This means the `robots.txt` file is not a foolproof way of ensuring AI scrapers don't grab your content.
If you want to block these things fully, you'll need to block based on the User-Agent header in a reverse proxy until GoToSocial can filter requests by User-Agent header.
A number of AI scrapers are known to ignore entries in `robots.txt` even if it explicitly matches their User-Agent. This means the `robots.txt` file is not a foolproof way of ensuring AI scrapers don't grab your content. In addition to this you might want to look into blocking User-Agents via [requester header filtering](request_filtering_modes.md).
[airobots]: https://github.com/ai-robots-txt/ai.robots.txt/

View file

@ -123,7 +123,13 @@ If you check this box, then any existing domain permissions will become managed
1. They don't already have a subscription ID (ie., they're not managed by any domain permission subscription).
2. They match a domain permission included in the list at the URL of this subscription.
For more information on orphan permissions, please see the separate [domain permission subscriptions](./domain_permission_subscriptions.md) document.
For more information on orphan permissions, please see the separate [domain permission subscriptions](./domain_permission_subscriptions.md#orphan-permissions) document.
##### Remove Retracted Permissions
This setting controls how retractions are handled by this domain permission subscription: if "Remove retracted permissions" is checked, retracted entries will be removed from the database; if "Remove retracted permissions" is not checked, retracted entries will just be orphaned instead.
For more detail on how retractions work, with examples, please see the separate [domain permission subscriptions](./domain_permission_subscriptions.md#retractions) document.
##### Create Permissions as Drafts

View file

@ -0,0 +1,43 @@
# Managing GtS on slow hardware
While GoToSocial runs great on lower-end hardware, some operations are not practical on it, especially
instances with the database on slow storage (think anything that is not an SSD). This document
offers some suggestions on how to work around common issues when running GtS on slow hardware.
## Running database migrations on a different machine
Sometimes a database migration will need to do operations that are taxing on the database's storage.
These operations can take days if the database resides on a hard disk or SD card. If your
database is on slow storage, it can save a lot of time to follow the following procedure:
!!! danger
It might seem tempting to keep GtS running while you run the migrations on another machine, but
doing this will lead to all the posts that are received during the migration post disappearing
once the migrated database is re-imported.
1. Shut down GtS
2. Take a [backup](backup_and_restore.md#what-to-backup-database) of the database
3. Import the database on faster hardware
4. Run the GtS migration on the faster hardware
5. Take a backup of the resultant database
6. Import the resultant backup and overwrite the old database
7. Start GtS with the new version
### Running GtS migrations separately
After you import the database on the faster hardware, you can run the migration without starting
GtS by downloading the *target* GtS version from the [releases](https://codeberg.org/superseriousbusiness/gotosocial/releases) page.
For instance, if you are running `v0.19.2` and you want to upgrade to `v0.20.0-rc1`, download the
latter version. Once you have the binary, set it to executable by running `chmod u+x /path/to/gotosocial`. Afterwards, copy the configuration of the original server, and alter
it with the location of the new database. We copy the configuration in case variables like
the hostname is used in the migration, we want to keep that consistent.
Once everything is in place, you can run the migration like this:
```sh
$ /path/to/gotosocial --config-path /path/to/config migrations run
```
This will run all the migrations, just like GtS would if it was started normally. Once this is done
you can copy the result to the original instance and start the new GtS version there as well, which
will see that everything is migrated and that there's nothing to do except run as expected.

View file

@ -1,32 +1,89 @@
# Metrics
GoToSocial comes with [OpenTelemetry][otel] based metrics. The metrics are exposed using the [Prometheus exposition format][prom] on the `/metrics` path. The configuration settings are documented in the [Observability configuration reference][obs].
GoToSocial uses the [OpenTelemetry][otel] Go SDK to enable instance admins to expose runtime metrics in the Prometheus metrics format.
Currently the following metrics are collected:
Currently, the following metrics are collected:
* Go performance and runtime metrics
* Gin (HTTP) metrics
* Gin (HTTP server) metrics
* Bun (database) metrics
Metrics can be enable with the following configuration:
## Enabling metrics
To enable metrics, first set the `metrics-enabled` configuration value to `true` in your config.yaml file:
```yaml
metrics-enabled: true
```
Though metrics do not contain anything privacy sensitive, you may not want to allow just anyone to view and scrape operational metrics of your instance.
Then, you will need to set some additional environment variables on the GoToSocial process in order to configure OpenTelemetry to expose metrics in the Prometheus format:
```env
OTEL_METRICS_PRODUCERS=prometheus
OTEL_METRICS_EXPORTER=prometheus
```
By default, this configuration will instantiate an additional HTTP server running alongside the standard GoToSocial HTTP server, which exposes a Prometheus metrics endpoint at `localhost:9464/metrics`.
!!! tip
If you are running GoToSocial using the [example systemd service definition](../../example/gotosocial.service), you can easily set these environment variables by uncommenting the relevant two lines in that file, and reloading + restarting the service.
If you wish, you can further customize this metrics HTTP server by using the following environment variables to change the host and port:
```env
OTEL_EXPORTER_PROMETHEUS_HOST=example.org
OTEL_EXPORTER_PROMETHEUS_PORT=9999
```
## Serving metrics to the outside world
If you have deployed GoToSocial in a "bare-metal" fashion without a reverse proxy, you can expose the metrics endpoint to the outside world by setting `OTEL_EXPORTER_PROMETHEUS_HOST` to your host value. For example, if your GtS instance `host` configuration value is set to `example.org`, you should set `OTEL_EXPORTER_PROMETHEUS_HOST=example.org`. You should then be able to access your metrics at `http://example.org:9464/metrics`. GoToSocial running in this fashion will not serve LetsEncrypt certificates at the metrics endpoint, so you will be limited to using HTTP rather than HTTPS.
If you are using a reverse proxy like Nginx, you can expose the metrics endpoint to the outside world with HTTPS certificates, by putting an additional location stanza in your Nginx configuration above the catch-all `location /` stanza:
```nginx
location /metrics {
proxy_pass http://127.0.0.1:9464;
}
```
This will instruct Nginx to forward requests to `example.org/metrics` to the separate Prometheus server running on port 9464.
## Enabling basic authentication
You can enable basic authentication for the metrics endpoint. On the GoToSocial, side you'll need the following configuration:
Although there is no sensitive data contained in the OTEL runtime statistics exported by Prometheus, you may nevertheless wish to gate access to the `/metrics` endpoint behind some kind of authentication, to prevent every Tom, Dick, and Harry from looking at your runtime stats.
```yaml
metrics-auth-enabled: true
metrics-auth-username: some_username
metrics-auth-password: some_password
You can do this by configuring your reverse proxy to require basic authentication for access to `/metrics`.
In Nginx, for example, you could do this by creating an `htpasswd` file alongside your site in the `sites-available` directory of Nginx, and instructing Nginx to use that file to gate access.
Assuming you followed the [guide for setting up Nginx as your reverse proxy](../getting_started/reverse_proxy/nginx.md), you will already have a file for your Nginx service definition at `/etc/nginx/sites-available/example.org`, where `example.org` is the hostname of your instance.
You can create an `htpasswd` file alongside this file using the following command:
```bash
htpasswd -c /etc/nginx/sites-available/example.org.htpasswd username
```
You can scrape that endpoint with a Prometheus instance using the following configuration in your `scrape_configs`:
In the command, be sure to replace `example.org` with your hostname, and `username` with whatever username you want to use.
Now, edit `/etc/nginx/sites-available/example.org` and update your `/metrics` stanza to use the `httpasswd` file. After editing it should look something like this:
```nginx
location /metrics {
proxy_pass http://127.0.0.1:9464;
auth_basic "Metrics";
auth_basic_user_file /etc/nginx/sites-available/example.org.htpasswd;
}
```
Again, replace `example.org` in that snippet with your instance hostname.
When you're finished editing, reload + restart Nginx, and you should see a basic authentication prompt when visiting the `/metrics` endpoint of your instance in your browser.
## Prometheus scrape configuration
You can scrape your `/metrics` endpoint with a Prometheus instance using the following configuration in your `scrape_configs`:
```yaml
- job_name: gotosocial
@ -40,18 +97,12 @@ You can scrape that endpoint with a Prometheus instance using the following conf
- example.org
```
## Blocking external scraping
Change `example.org` to your hostname in the above snippet. If you are not using HTTPS, change the `scheme` value to `http`. If you are not using basic authentication, you can remove the `basic_auth` section. If you are not using a reverse proxy, and metrics are exposed on port 9464, add the port to the host (eg., `example.org` -> `example.org:9464`).
When running with a reverse proxy you can use it to block external access to metrics. You can use this approach if your Prometheus scraper runs on the same machine as your GoToSocial instance and can thus access it internally.
## Viewing metrics on Grafana
For example with nginx, block the `/metrics` endpoint by returning a 404:
```nginx
location /metrics {
return 404;
}
```
Instructions on how to set up Grafana are beyond the scope of this document. However, once you have set up a Grafana to pull from your Prometheus instance, you can import the [example Grafana dashboard](https://codeberg.org/superseriousbusiness/gotosocial/raw/branch/main/example/metrics/gotosocial_grafana_dashboard.json) into your Grafana frontend to easily view GoToSocial Go runtime and HTTP metrics.
[otel]: https://opentelemetry.io/
[prom]: https://prometheus.io/docs/instrumenting/exposition_formats/
[obs]: ../configuration/observability.md
[obs]: ../configuration/observability_and_metrics.md

View file

@ -1,25 +1,20 @@
# Tracing
GoToSocial comes with [OpenTelemetry][otel] based tracing built-in. It's not wired through every function, but our HTTP handlers and database library will create spans. How to configure tracing is explained in the [Observability configuration reference][obs].
GoToSocial comes with [OpenTelemetry][otel] based tracing built-in. It's not wired through every function, but our HTTP handlers and database library will create spans that may help you debug issues.
## Enabling tracing
To enable tracing on your instance, you must set `tracing-enabled` to `true` in your config.yaml file. Then, you must set the environment variable `OTEL_TRACES_EXPORTER` to your desired tracing format. A list of available options is available [here](https://opentelemetry.io/docs/languages/sdk-configuration/general/#otel_traces_exporter). Once you have changed your config and set the environment variable, restart your instance.
If necessary, you can do further configuration of tracing using the other environment variables listed [here](https://opentelemetry.io/docs/languages/sdk-configuration/general/).
## Ingesting traces
In order to receive the traces, you need something to ingest them and then visualise them. There are many options available including self-hosted and commercial options.
We provide an example of how to do this using [Grafana Tempo][tempo] to ingest the spans and [Grafana][grafana] to explore them. Please beware that the configuration we provide is not suitable for a production setup. It can be used safely for local development and can provide a good starting point for setting up your own tracing infrastructure.
In [`example/tracing`][ext] we provide an example of how to do this using [Grafana Tempo][tempo] to ingest the spans and [Grafana][grafana] to explore them. You can use the files with `docker-compose up -d` to get Tempo and Grafana running.
You'll need the files in [`example/tracing`][ext]. Once you have those you can run `docker-compose up -d` to get Tempo and Grafana running. With both services running, you can add the following to your GoToSocial configuration and restart your instance:
```yaml
tracing-enabled: true
tracing-transport: "grpc"
tracing-endpoint: "localhost:4317"
tracing-insecure-transport: true
```
[otel]: https://opentelemetry.io/
[obs]: ../configuration/observability.md
[tempo]: https://grafana.com/oss/tempo/
[grafana]: https://grafana.com/oss/grafana/
[ext]: https://codeberg.org/superseriousbusiness/gotosocial/tree/main/example/tracing
Please be aware that while the example configuration we provide can be used safely for local development and can provide a good starting point for setting up your own tracing infrastructure, it is not suitable for a so-called "production" setup.
## Querying and visualising traces
@ -27,18 +22,23 @@ Once you execute a few queries against your instance, you'll be able to find the
Using TraceQL, a simple query to find all traces related to requests to `/api/v1/instance` would look like this:
```
```traceql
{.http.route = "/api/v1/instance"}
```
If you wanted to see all GoToSocial traces, you could instead run:
```
```traceql
{.service.name = "GoToSocial"}
```
Once you select a trace, a second panel will open up visualising the span. You can drill down from there, by clicking into every sub-span to see what it was doing.
![Grafana showing a trace for the /api/v1/instance endpoint](../public/tracing.png)
![Grafana showing a trace for the /api/v1/instance endpoint](../overrides/public/tracing.png)
[traceql]: https://grafana.com/docs/tempo/latest/traceql/
[otel]: https://opentelemetry.io/
[obs]: ../configuration/observability_and_metrics.md
[tempo]: https://grafana.com/oss/tempo/
[grafana]: https://grafana.com/oss/grafana/
[ext]: https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/example/tracing

View file

@ -130,6 +130,69 @@ definitions:
title: NodeInfoUsers represents aggregate information about the users on the server.
type: object
x-go-package: code.superseriousbusiness.org/gotosocial/internal/api/model
ScheduledStatusParams:
properties:
application_id:
type: string
x-go-name: ApplicationID
content_type:
type: string
x-go-name: ContentType
in_reply_to_id:
type: string
x-go-name: InReplyToID
interaction_policy:
$ref: '#/definitions/interactionPolicy'
language:
type: string
x-go-name: Language
local_only:
type: boolean
x-go-name: LocalOnly
media_ids:
items:
type: string
type: array
x-go-name: MediaIDs
poll:
$ref: '#/definitions/ScheduledStatusParamsPoll'
scheduled_at:
type: string
x-go-name: ScheduledAt
sensitive:
type: boolean
x-go-name: Sensitive
spoiler_text:
type: string
x-go-name: SpoilerText
text:
type: string
x-go-name: Text
visibility:
type: string
x-go-name: Visibility
title: StatusParams represents parameters for a scheduled status.
type: object
x-go-package: code.superseriousbusiness.org/gotosocial/internal/api/model
ScheduledStatusParamsPoll:
properties:
expires_in:
format: int64
type: integer
x-go-name: ExpiresIn
hide_totals:
type: boolean
x-go-name: HideTotals
multiple:
type: boolean
x-go-name: Multiple
options:
items:
type: string
type: array
x-go-name: Options
type: object
x-go-package: code.superseriousbusiness.org/gotosocial/internal/api/model
Source:
description: Returned as an additional entity when verifying and updated credentials, as an attribute of Account.
properties:
@ -1101,7 +1164,7 @@ definitions:
properties:
comment:
description: |-
If the domain is blocked, what's the publicly-stated reason for the block.
If the domain is blocked or allowed, what's the publicly-stated reason (if any).
Alternative to `public_comment` to be used when serializing/deserializing via /api/v1/instance.
example: they smell
type: string
@ -1113,11 +1176,17 @@ definitions:
x-go-name: Domain
public_comment:
description: |-
If the domain is blocked, what's the publicly-stated reason for the block.
If the domain is blocked or allowed, what's the publicly-stated reason (if any).
Alternative to `comment` to be used when serializing/deserializing NOT via /api/v1/instance.
example: they smell
type: string
x-go-name: PublicComment
severity:
description: |-
Severity of this entry.
Only ever set for domain blocks, and if set, always="suspend".
type: string
x-go-name: Severity
silenced_at:
description: Time at which this domain was silenced. Key will not be present on open domains.
example: "2021-07-30T09:20:25+00:00"
@ -1135,7 +1204,7 @@ definitions:
properties:
comment:
description: |-
If the domain is blocked, what's the publicly-stated reason for the block.
If the domain is blocked or allowed, what's the publicly-stated reason (if any).
Alternative to `public_comment` to be used when serializing/deserializing via /api/v1/instance.
example: they smell
type: string
@ -1179,11 +1248,17 @@ definitions:
x-go-name: PrivateComment
public_comment:
description: |-
If the domain is blocked, what's the publicly-stated reason for the block.
If the domain is blocked or allowed, what's the publicly-stated reason (if any).
Alternative to `comment` to be used when serializing/deserializing NOT via /api/v1/instance.
example: they smell
type: string
x-go-name: PublicComment
severity:
description: |-
Severity of this entry.
Only ever set for domain blocks, and if set, always="suspend".
type: string
x-go-name: Severity
silenced_at:
description: Time at which this domain was silenced. Key will not be present on open domains.
example: "2021-07-30T09:20:25+00:00"
@ -1277,6 +1352,11 @@ definitions:
format: uint8
type: integer
x-go-name: Priority
remove_retracted:
description: If true, then when a list is processed, if the list does *not* contain entries that it *did* contain previously, ie., retracted entries, then domain permissions corresponding to those entries will be removed. If false, they will just be orphaned instead.
example: true
type: boolean
x-go-name: RemoveRetracted
successfully_fetched_at:
description: Time of the most recent successful fetch (ISO 8601 Datetime).
example: "2021-07-30T09:20:25+00:00"
@ -1581,9 +1661,7 @@ definitions:
type: integer
x-go-name: MaxFeaturedTags
max_profile_fields:
description: |-
The maximum number of profile fields allowed for each account.
Currently not configurable, so this is hardcoded to 6. (https://codeberg.org/superseriousbusiness/gotosocial/issues/1876)
description: The maximum number of profile fields allowed for each account.
format: int64
type: integer
x-go-name: MaxProfileFields
@ -2098,6 +2176,20 @@ definitions:
example: <p>Registrations are currently closed on example.org because of spam bots!</p>
type: string
x-go-name: Message
min_age:
description: |-
A minimum age required to register, if configured.
Currently not implemented: will always be null.
format: int64
type: integer
x-go-name: MinAge
reason_required:
description: |-
Whether registrations require the user to provide a reason for joining.
Only applicable when ApprovalRequired is true.
example: true
type: boolean
x-go-name: ReasonRequired
title: Information about registering for this instance.
type: object
x-go-name: InstanceV2Registrations
@ -2168,11 +2260,26 @@ definitions:
x-go-package: code.superseriousbusiness.org/gotosocial/internal/api/model
instanceV2URLs:
properties:
about:
description: Address of the server about page.
example: https://example.org/about
type: string
x-go-name: About
privacy_policy:
description: Address of the server privacy policy, if any.
example: https://example.org/about#rules
type: string
x-go-name: PrivacyPolicy
streaming:
description: Websockets address for status and notification streaming.
example: wss://example.org
type: string
x-go-name: Streaming
terms_of_service:
description: Address of the server current terms of service, if any.
example: https://example.org/about#privacy_policy
type: string
x-go-name: TermsOfService
title: InstanceV2URLs models instance-relevant URLs for client application consumption.
type: object
x-go-name: InstanceV2URLs
@ -2214,13 +2321,29 @@ definitions:
interactionPolicyRules:
properties:
always:
description: Policy entries for accounts that can always do this type of interaction.
description: |-
Policy entries for accounts that can always do this type of interaction.
Deprecated: Use "automatic_approval" instead.
items:
$ref: '#/definitions/interactionPolicyValue'
type: array
x-go-name: Always
automatic_approval:
description: Policy entries for accounts that will receive automatic approval for this type of interaction.
items:
$ref: '#/definitions/interactionPolicyValue'
type: array
x-go-name: AutomaticApproval
manual_approval:
description: Policy entries for accounts that require manual approval for this type of interaction.
items:
$ref: '#/definitions/interactionPolicyValue'
type: array
x-go-name: ManualApproval
with_approval:
description: Policy entries for accounts that require approval to do this type of interaction.
description: |-
Policy entries for accounts that require approval to do this type of interaction.
Deprecated: Use "manual_approval" instead.
items:
$ref: '#/definitions/interactionPolicyValue'
type: array
@ -2279,10 +2402,6 @@ definitions:
`reblog` - Someone reblogged / boosted a status.
type: string
x-go-name: Type
uri:
description: URI of the Accept or Reject. Only set if accepted_at or rejected_at is set, else omitted.
type: string
x-go-name: URI
title: InteractionRequest represents a pending, approved, or rejected interaction of type favourite, reply, or reblog.
type: object
x-go-name: InteractionRequest
@ -2849,6 +2968,25 @@ definitions:
type: object
x-go-name: Report
x-go-package: code.superseriousbusiness.org/gotosocial/internal/api/model
scheduledStatus:
properties:
id:
type: string
x-go-name: ID
media_attachments:
items:
$ref: '#/definitions/attachment'
type: array
x-go-name: MediaAttachments
params:
$ref: '#/definitions/ScheduledStatusParams'
scheduled_at:
type: string
x-go-name: ScheduledAt
title: ScheduledStatus represents a status that will be published at a future scheduled date.
type: object
x-go-name: ScheduledStatus
x-go-package: code.superseriousbusiness.org/gotosocial/internal/api/model
searchResult:
properties:
accounts:
@ -3726,6 +3864,7 @@ info:
read:applications: grants read access to user-managed applications
read:blocks: grants read access to blocks
read:bookmarks: grants read access to bookmarks
read:custom_emojis: grants read access to custom emojis
read:favourites: grants read access to accounts
read:filters: grants read access to filters
read:follows: grants read access to follows
@ -6695,6 +6834,11 @@ paths:
in: formData
name: adopt_orphans
type: boolean
- default: true
description: If true, then when a list is processed, if the list does *not* contain entries that it *did* contain previously, ie., retracted entries, then domain permissions corresponding to those entries will be removed. If false, they will just be orphaned instead.
in: formData
name: remove_retracted
type: boolean
- description: URI to call in order to fetch the permissions list.
in: formData
name: uri
@ -6774,6 +6918,11 @@ paths:
in: formData
name: adopt_orphans
type: boolean
- default: true
description: If true, then when a list is processed, if the list does *not* contain entries that it *did* contain previously, ie., retracted entries, then domain permissions corresponding to those entries will be removed. If false, they will just be orphaned instead.
in: formData
name: remove_retracted
type: boolean
- description: MIME content type to use when parsing the permissions list. One of "text/plain", "text/csv", and "application/json".
in: formData
name: content_type
@ -8100,6 +8249,7 @@ paths:
- conversations
/api/v1/custom_emojis:
get:
description: If the instance config setting `instance-expose-custom-emojis` is `true` then authentication is not required.
operationId: customEmojisGet
produces:
- application/json
@ -8117,7 +8267,8 @@ paths:
"500":
description: internal server error
security:
- OAuth2 Bearer: []
- OAuth2 Bearer:
- read:custom_emojis
summary: Get an array of custom emojis available on the instance.
tags:
- custom_emojis
@ -8719,6 +8870,65 @@ paths:
summary: Reject/deny follow request from the given account ID.
tags:
- follow_requests
/api/v1/follow_requests/outgoing:
get:
description: |-
The next and previous queries can be parsed from the returned Link header.
Example:
```
<https://example.org/api/v1/follow_requests/outgoing?limit=80&max_id=01FC0SKA48HNSVR6YKZCQGS2V8>; rel="next", <https://example.org/api/v1/follow_requests/outgoing?limit=80&min_id=01FC0SKW5JK2Q4EVAV2B462YY0>; rel="prev"
````
operationId: getOutgoingFollowRequests
parameters:
- description: 'Return only follow requested accounts *OLDER* than the given max ID. The follow requestee with the specified ID will not be included in the response. NOTE: the ID is of the internal follow request, NOT any of the returned accounts.'
in: query
name: max_id
type: string
- description: 'Return only follow requested accounts *NEWER* than the given since ID. The follow requestee with the specified ID will not be included in the response. NOTE: the ID is of the internal follow request, NOT any of the returned accounts.'
in: query
name: since_id
type: string
- description: 'Return only follow requested accounts *IMMEDIATELY NEWER* than the given min ID. The follow requestee with the specified ID will not be included in the response. NOTE: the ID is of the internal follow request, NOT any of the returned accounts.'
in: query
name: min_id
type: string
- default: 40
description: Number of follow requested accounts to return.
in: query
maximum: 80
minimum: 1
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: ""
headers:
Link:
description: Links to the next and previous queries.
type: string
schema:
items:
$ref: '#/definitions/account'
type: array
"400":
description: bad request
"401":
description: unauthorized
"404":
description: not found
"406":
description: not acceptable
"500":
description: internal server error
security:
- OAuth2 Bearer:
- read:follows
summary: Get an array of accounts that you have requested to follow.
tags:
- follow_requests
/api/v1/followed_tags:
get:
operationId: getFollowedTags
@ -8914,37 +9124,105 @@ paths:
summary: Update your instance information and/or upload a new avatar/header for the instance.
tags:
- instance
/api/v1/instance/domain_allows:
get:
description: OAuth token may need to be provided depending on setting `instance-expose-allowlist`.
operationId: instanceDomainAllowsGet
produces:
- application/json
responses:
"200":
description: List of explicitly allowed domains.
schema:
items:
$ref: '#/definitions/domain'
type: array
"400":
description: bad request
"401":
description: unauthorized
"403":
description: forbidden
"404":
description: not found
"406":
description: not acceptable
"500":
description: internal server error
security:
- OAuth2 Bearer: []
summary: List explicitly allowed domains.
tags:
- instance
/api/v1/instance/domain_blocks:
get:
description: OAuth token may need to be provided depending on setting `instance-expose-blocklist`.
operationId: instanceDomainBlocksGet
produces:
- application/json
responses:
"200":
description: List of blocked domains.
schema:
items:
$ref: '#/definitions/domain'
type: array
"400":
description: bad request
"401":
description: unauthorized
"403":
description: forbidden
"404":
description: not found
"406":
description: not acceptable
"500":
description: internal server error
security:
- OAuth2 Bearer: []
summary: List blocked domains.
tags:
- instance
/api/v1/instance/peers:
get:
operationId: instancePeersGet
parameters:
- default: open
- default: flat
description: |-
Comma-separated list of filters to apply to results. Recognized filters are:
- `open` -- include peers that are not suspended or silenced
- `suspended` -- include peers that have been suspended.
- `open` -- include known domains that are not in the domain blocklist
- `allowed` -- include domains that are in the domain allowlist
- `blocked` -- include domains that are in the domain blocklist
- `suspended` -- DEPRECATED! Use `blocked` instead. Same as `blocked`: include domains that are in the domain blocklist;
If filter is `open`, only instances that haven't been suspended or silenced will be returned.
If filter is `open`, only domains that aren't in the blocklist will be shown.
If filter is `suspended`, only suspended instances will be shown.
If filter is `blocked`, only domains that *are* in the blocklist will be shown.
If filter is `open,suspended`, then all known instances will be returned.
If filter is `allowed`, only domains that are in the allowlist will be shown.
If filter is `open,blocked`, then blocked domains and known domains not on the blocklist will be shown.
If filter is `open,allowed`, then allowed domains and known domains not on the blocklist will be shown.
If filter is an empty string or not set, then `open` will be assumed as the default.
in: query
name: filter
type: string
- default: false
description: If true, a "flat" array of strings will be returned corresponding to just domain names.
in: query
name: flat
type: boolean
produces:
- application/json
responses:
"200":
description: |-
If no filter parameter is provided, or filter is empty, then a legacy, Mastodon-API compatible response will be returned. This will consist of just a 'flat' array of strings like `["example.com", "example.org"]`, which corresponds to domains this instance peers with.
If a filter parameter is provided, then an array of objects with at least a `domain` key set on each object will be returned.
If no filter parameter is provided, or filter is empty, then a legacy, Mastodon-API compatible response will be returned. This will consist of just a 'flat' array of strings like `["example.com", "example.org"]`, which corresponds to setting a filter of `open` and flat=true.
If a filter parameter is provided and flat is not true, then an array of objects with at least a `domain` key set on each object will be returned.
Domains that are silenced or suspended will also have a key `suspended_at` or `silenced_at` that contains an iso8601 date string. If one of these keys is not present on the domain object, it is open. Suspended instances may in some cases be obfuscated, which means they will have some letters replaced by `*` to make it more difficult for bad actors to target instances with harassment.
Whether a flat response or a more detailed response is returned, domains will be sorted alphabetically by hostname.
schema:
items:
@ -8964,6 +9242,7 @@ paths:
description: internal server error
security:
- OAuth2 Bearer: []
summary: List peer domains.
tags:
- instance
/api/v1/instance/rules:
@ -9354,7 +9633,7 @@ paths:
security:
- OAuth2 Bearer:
- read:lists
summary: Get all lists for owned by authorized user.
summary: Get all lists owned by authorized user.
tags:
- lists
post:
@ -10669,6 +10948,159 @@ paths:
summary: Get one report with the given id.
tags:
- reports
/api/v1/scheduled_statuses:
get:
operationId: getScheduledStatuses
parameters:
- description: Return only statuses *OLDER* than the given max status ID. The status with the specified ID will not be included in the response.
in: query
name: max_id
type: string
- description: Return only statuses *newer* than the given since status ID. The status with the specified ID will not be included in the response.
in: query
name: since_id
type: string
- description: Return only statuses *immediately newer* than the given min ID. The status with the specified ID will not be included in the response.
in: query
name: min_id
type: string
- default: 20
description: Number of scheduled statuses to return.
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: ""
headers:
Link:
description: Links to the next and previous queries.
type: string
schema:
items:
$ref: '#/definitions/scheduledStatus'
type: array
"400":
description: bad request
"401":
description: unauthorized
"404":
description: not found
"406":
description: not acceptable
"500":
description: internal server error
security:
- OAuth2 Bearer:
- read:statuses
summary: Get an array of statuses scheduled by authorized user.
tags:
- scheduled_statuses
/api/v1/scheduled_statuses/{id}:
delete:
operationId: deleteScheduledStatus
parameters:
- description: ID of the status
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: status canceled
"400":
description: bad request
"401":
description: unauthorized
"404":
description: not found
"406":
description: not acceptable
"500":
description: internal server error
security:
- OAuth2 Bearer:
- write:statuses
summary: Cancel a scheduled status with the given id.
tags:
- scheduled_statuses
get:
operationId: getScheduledStatus
parameters:
- description: ID of the status
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: ""
schema:
$ref: '#/definitions/scheduledStatus'
"400":
description: bad request
"401":
description: unauthorized
"404":
description: not found
"406":
description: not acceptable
"500":
description: internal server error
security:
- OAuth2 Bearer:
- read:statuses
summary: Get a scheduled status with the given id.
tags:
- scheduled_statuses
put:
operationId: updateScheduledStatus
parameters:
- description: ID of the status
in: path
name: id
required: true
type: string
- description: |-
ISO 8601 Datetime at which to schedule a status.
Must be at least 5 minutes in the future.
format: date-time
in: formData
name: scheduled_at
type: string
x-go-name: ScheduledAt
produces:
- application/json
responses:
"200":
description: ""
schema:
$ref: '#/definitions/scheduledStatus'
"400":
description: bad request
"401":
description: unauthorized
"404":
description: not found
"406":
description: not acceptable
"422":
description: unprocessable content
"500":
description: internal server error
security:
- OAuth2 Bearer:
- write:statuses
summary: Update a scheduled status's publishing date.
tags:
- scheduled_statuses
/api/v1/statuses:
post:
consumes:
@ -10793,7 +11225,6 @@ paths:
Providing this parameter with a *future* time will cause ScheduledStatus to be returned instead of Status.
Must be at least 5 minutes in the future.
This feature isn't implemented yet.
Providing this parameter with a *past* time will cause the status to be backdated,
and will not push it to the user's followers. This is intended for importing old statuses.
@ -10856,10 +11287,10 @@ paths:
description: not found
"406":
description: not acceptable
"422":
description: unprocessable content
"500":
description: internal server error
"501":
description: scheduled_at was set, but this feature is not yet implemented
security:
- OAuth2 Bearer:
- write:statuses
@ -11146,7 +11577,7 @@ paths:
description: internal server error
security:
- OAuth2 Bearer:
- write:statuses
- write:favourites
summary: Star/like/favourite the given status, if permitted.
tags:
- statuses
@ -11684,6 +12115,32 @@ paths:
summary: Initiate a websocket connection for live streaming of statuses and notifications.
tags:
- streaming
/api/v1/suggestions:
get:
description: 'THIS ENDPOINT IS CURRENTLY NOT FULLY IMPLEMENTED: it will always return an empty array.'
operationId: getSuggestions
produces:
- application/json
responses:
"200":
description: ""
schema:
items:
type: object
maxItems: 0
type: array
"401":
description: unauthorized
"403":
description: forbidden
"406":
description: not acceptable
security:
- OAuth2 Bearer:
- read
summary: Accounts that are promoted by staff, or that the user has had past positive interactions with, but is not yet following.
tags:
- suggestions
/api/v1/tags/{tag_name}:
get:
description: If the tag does not exist, this method will not create it in the database.
@ -12136,6 +12593,63 @@ paths:
summary: Invalidate the target token, removing it from the database and making it unusable.
tags:
- tokens
/api/v1/trends/links:
get:
description: 'THIS ENDPOINT IS CURRENTLY NOT FULLY IMPLEMENTED: it will always return an empty array.'
operationId: getTrendingLinks
produces:
- application/json
responses:
"200":
description: ""
schema:
items:
type: object
maxItems: 0
type: array
"406":
description: not acceptable
summary: Links that have been shared more than others.
tags:
- trends
/api/v1/trends/statuses:
get:
description: 'THIS ENDPOINT IS CURRENTLY NOT FULLY IMPLEMENTED: it will always return an empty array.'
operationId: getTrendingStatuses
produces:
- application/json
responses:
"200":
description: ""
schema:
items:
type: object
maxItems: 0
type: array
"406":
description: not acceptable
summary: Statuses that have been interacted with more than others.
tags:
- trends
/api/v1/trends/tags:
get:
description: 'THIS ENDPOINT IS CURRENTLY NOT FULLY IMPLEMENTED: it will always return an empty array.'
operationId: getTrendingTags
produces:
- application/json
responses:
"200":
description: ""
schema:
items:
type: object
maxItems: 0
type: array
"406":
description: not acceptable
summary: View hashtags that are currently being used more frequently than usual.
tags:
- trends
/api/v1/user:
get:
operationId: getUser
@ -13434,6 +13948,7 @@ securityDefinitions:
read:applications: grants read access to user-managed applications
read:blocks: grants read access to blocks
read:bookmarks: grants read access to bookmarks
read:custom_emojis: grants read access to custom emojis
read:favourites: grants read access to accounts
read:filters: grants read access to filters
read:follows: grants read access to follows

View file

@ -64,4 +64,12 @@ accounts-allow-custom-css: false
# Examples: [500, 5000, 9999]
# Default: 10000
accounts-custom-css-length: 10000
# Int. The maximum number of profile fields allowed for each account.
#
# Note that going way higher than the default might break federation.
#
# Examples: [4, 6, 12]
# Default: 6
accounts-max-profile-fields: 6
```

View file

@ -2,21 +2,21 @@
GoToSocial stores statuses, accounts, etc, in a database. This can be either [SQLite](https://sqlite.org/index.html) or [Postgres](https://www.postgresql.org/).
By default, GoToSocial will use Postgres, but this is easy to change.
GoToSocial has no default configured database type or address. In most situations, we recommend the use of SQLite.
## SQLite
SQLite, as the name implies, is the lightest database type that GoToSocial can use. It stores entries in a simple file format, usually in the same directory as the GoToSocial binary itself. SQLite is great for small instances and single-board computers, where a dedicated database would be overkill.
To configure GoToSocial to use SQLite, change `db-type` to `sqlite`. The `address` setting will then be a filename instead of an address, so you will want to change it to `sqlite.db` or something similar.
To use SQLite, keep the default `db-type` as `sqlite`. By default the database will be kept in the same directory as the GoToSocial binary, ie., `./sqlite.db`, but you can change this using `db-address` if you want to keep it somewhere else. In the same directory as the `sqlite.db` file, the SQLite driver will also create files `sqlite.db-wal` and `sqlite.db-shm` for temporary storage.
Note that the `:memory:` setting will use an *in-memory database* which will be wiped when your GoToSocial instance stops running. This is for testing only and is absolutely not suitable for running a proper instance, so *don't do this*.
## Postgres
Postgres is a heavier database format, which is useful for larger instances where you need to scale performance, or where you need to run your database on a dedicated machine separate from your GoToSocial instance (or do funky stuff like run a database cluster).
Postgres (aka PostgreSQL) is a heavier database which is useful for larger instances where you need to run your database on a dedicated machine separate from your GoToSocial instance (or do funky stuff like run a database cluster).
You can connect to Postgres using either a Unix socket connection, or via TCP, depending on what you've set as your `db-address` value.
To configure GoToSocial to use Postgres, change `db-type` to `postgres`. The `db-address` setting will then be either a Unix socket connection or a hostname.
GoToSocial also supports connecting to Postgres using SSL/TLS over TCP. If you're running Postgres on a different machine from GoToSocial, and connecting to it via an IP address or hostname (as opposed to just running on localhost), then SSL/TLS is **CRUCIAL** to avoid leaking data all over the place!
@ -71,8 +71,8 @@ db-postgres-connection-string: 'postgres://myUser:myPass@localhost/db?search_pat
# String. Database type.
# Options: ["postgres","sqlite"]
# Default: "postgres"
db-type: "postgres"
# Default: ""
db-type: "sqlite"
# String. Database address or parameters.
#
@ -87,29 +87,29 @@ db-type: "postgres"
#
# Examples: ["localhost","my.db.host","127.0.0.1","192.111.39.110",":memory:", "sqlite.db"]
# Default: ""
db-address: ""
db-address: "sqlite.db"
# Int. Port for database connection.
# Int. Port for postgres database connection; ignored for sqlite.
# Examples: [5432, 1234, 6969]
# Default: 5432
db-port: 5432
# String. Username for the database connection.
# String. Username for postgres database connection.
# Examples: ["mydbuser","postgres","gotosocial"]
# Default: ""
db-user: ""
# String. Password to use for the database connection
# String. Password to use for postgres database connection.
# Examples: ["password123","verysafepassword","postgres"]
# Default: ""
db-password: ""
# String. Name of the database to use within the provided database type.
# String. Name of the database to use for postgres database connection.
# Examples: ["mydb","postgres","gotosocial"]
# Default: "gotosocial"
db-database: "gotosocial"
# String. Disable, enable, or require SSL/TLS connection to the database.
# String. Disable, enable, or require SSL/TLS connection to postgres.
# If "disable" then no TLS connection will be attempted.
# If "enable" then TLS will be tried, but the database certificate won't be checked (for self-signed certs).
# If "require" then TLS will be required to make a connection, and a valid certificate must be presented.

View file

@ -26,6 +26,19 @@ log-db-queries: false
# Default: true
log-client-ip: true
# String. Format to use for formatting log entries.
# Supports "logfmt" and "json", with examples below:
#
# logfmt:
# func=router.(*Router).Start.func1 level=INFO msg="listening on 127.0.0.1:8080"
#
# json:
# {"func":"router.(*Router).Start.func1", "level":"INFO", "msg":"listening on 127.0.0.1:8080"}
#
# Examples: ["logfmt", "json"]
# Default: "logfmt"
log-format: "logfmt"
# String. Format to use for the timestamp in log lines.
# If set to the empty string, the timestamp will be
# ommitted from the logs entirely.
@ -94,14 +107,16 @@ account-domain: ""
# Default: "https"
protocol: "https"
# String. Address to bind the GoToSocial server to.
# This can be an IPv4 address or an IPv6 address (surrounded in square brackets), or a hostname.
# String. Address to bind the GoToSocial HTTP server to.
# This can be an IPv4 address, an IPv6 address, or a hostname.
#
# The default value will bind to all interfaces, which makes the server
# accessible by other machines. For most setups there is no need to change this.
# If you are using GoToSocial in a reverse proxy setup with the proxy running on
# the same machine, you will want to set this to "localhost" or an equivalent,
# so that the proxy can't be bypassed.
# Examples: ["0.0.0.0", "172.128.0.16", "localhost", "[::]", "[2001:db8::fed1]"]
# accessible by other machines. For most setups you won't need to change this.
# However, if you are using GoToSocial in a reverse proxy setup with the proxy
# running on the same machine, you may want to set this to "localhost" or equivalent,
# so that the proxy definitely can't be bypassed.
#
# Examples: ["0.0.0.0", "172.128.0.16", "localhost", "::1", "2001:db8::fed1"]
# Default: "0.0.0.0"
bind-address: "0.0.0.0"

View file

@ -60,9 +60,18 @@ http-client:
#
# THIS SETTING SHOULD BE USED FOR TESTING ONLY! IF YOU TURN THIS
# ON WHILE RUNNING IN PRODUCTION YOU ARE LEAVING YOUR SERVER WIDE
# OPEN TO MAN IN THE MIDDLE ATTACKS! DO NOT CHANGE THIS SETTING
# OPEN TO MAN IN THE MIDDLE ATTACKS! DO NOT CHANGE THIS SETTING
# UNLESS YOU KNOW EXACTLY WHAT YOU'RE DOING AND WHY YOU'RE DOING IT.
#
# Default: false
tls-insecure-skip-verify: false
# Bool. Sets outgoing queries to webfinger, host-meta and nodeinfo to use
# HTTP instead of HTTPS.
#
# THIS SETTING SHOULD BE USED FOR TESTING ONLY! DO NOT CHANGE THIS SETTING
# UNLESS YOU KNOW EXACTLY WHAT YOU'RE DOING AND WHY YOU'RE DOING IT.
#
# Default: false
insecure-outgoing: false
```

View file

@ -76,29 +76,61 @@ instance-federation-mode: "blocklist"
# Default: false
instance-federation-spam-filter: false
# Bool. Allow unauthenticated users to make queries to /api/v1/instance/peers?filter=open in order
# to see a list of instances that this instance 'peers' with. Even if set to 'false', then authenticated
# users (members of the instance) will still be able to query the endpoint.
# Bool. Allow unauthenticated users to make queries to /api/v1/instance/peers?filter=open
# in order to see a list of domains that this instance 'peers' with.
#
# Even if set to 'false', then authenticated users (members of the instance)
# will still be able to query these endpoints using an OAuth token.
#
# Options: [true, false]
# Default: false
instance-expose-peers: false
# Bool. Allow unauthenticated users to make queries to /api/v1/instance/peers?filter=suspended in order
# to see a list of instances that this instance blocks/suspends. Even if set to 'false', then authenticated
# users (members of the instance) will still be able to query the endpoint.
# Bool. Allow unauthenticated users to make queries to the following instance API
# endpoints in order to see a list of domains that this instance explicitly blocks,
# including the public reason for each block:
#
# WARNING: Setting this variable to 'true' may result in your instance being scraped by blocklist scrapers.
# - /api/v1/instance/peers?filter=blocklist
# - /api/v1/instance/peers?filter=suspended (deprecated)
# - /api/v1/instance/domain_blocks
#
# Even if set to 'false', then authenticated users (members of the instance)
# will still be able to query these endpoints using an OAuth token.
#
# WARNING: Setting to 'true' may result in your instance being targeted by blocklist scrapers.
# See: https://docs.gotosocial.org/en/latest/admin/domain_blocks/#block-announce-bots
#
# Options: [true, false]
# Default: false
instance-expose-suspended: false
instance-expose-blocklist: false
# Bool. Allow unauthenticated users to view /about/suspended,
# showing the HTML rendered list of instances that this instance blocks/suspends.
# Bool. Allow unauthenticated users to view /about/domain_blocks,
# which shows an HTML-rendered list of domains that this instance blocks,
# including the public reason for each block.
# Options: [true, false]
# Default: false
instance-expose-suspended-web: false
instance-expose-blocklist-web: false
# Bool. Allow unauthenticated users to make queries to the following instance API
# endpoints in order to see a list of domains that this instance explicitly allows
# including the public reason for each allow:
#
# - /api/v1/instance/peers?filter=allowlist
# - /api/v1/instance/domain_allows
#
# Even if set to 'false', then authenticated users (members of the instance)
# will still be able to query these endpoints using an OAuth token.
#
# Options: [true, false]
# Default: false
instance-expose-allowlist: false
# Bool. Allow unauthenticated users to view /about/domain_allows,
# which shows an HTML-rendered list of domains that this instance allows,
# including the public reason for each allow.
# Options: [true, false]
# Default: false
instance-expose-allowlist-web: false
# Bool. Allow unauthenticated users to make queries to /api/v1/timelines/public in order
# to see a list of public posts on this server. Even if set to 'false', then authenticated
@ -107,6 +139,21 @@ instance-expose-suspended-web: false
# Default: false
instance-expose-public-timeline: false
# Bool. Allow unauthenticated access to /api/v1/custom_emojis, which
# exposes the list of custom emojis available to users on this server.
#
# Setting this to 'true' may alleviate issues with clients that do not
# provide an access token in their requests to the emojis endpoint, but
# it also means that anyone can look at what emojis are installed on your
# instance, which may present privacy / safety issues.
#
# Even if set to 'false', authenticated users (ie., instance members)
# will still be able to query the endpoint using an access token.
#
# Options: [true, false]
# Default: false
instance-expose-custom-emojis: false
# Bool. This flag tweaks whether GoToSocial will deliver ActivityPub messages
# to the shared inbox of a recipient, if one is available, instead of delivering
# each message to each actor who should receive a message individually.
@ -174,9 +221,7 @@ instance-stats-mode: ""
# Bool. This flag controls whether local accounts may backdate statuses
# using past dates with the scheduled_at param to /api/v1/statuses.
# This flag does not affect scheduling posts in the future
# (which is currently not implemented anyway),
# nor can it prevent remote accounts from backdating their own statuses.
# This flag can't prevent remote accounts from backdating their own statuses.
#
# If true, all local accounts may backdate statuses.
# If false, status backdating will be disabled and an error will be returned if it's used.

View file

@ -1,57 +0,0 @@
# Observability
These settings let you tune and configure certain observability related behaviours.
## Metrics
Before enabling metrics, [read the guide](../advanced/metrics.md) and ensure you've taken the appropriate security measures for your setup.
## Settings
```yaml
##################################
##### OBSERVABILITY SETTINGS #####
##################################
# String. Header name to use to extract a request or trace ID from. Typically set by a
# loadbalancer or proxy.
# Default: "X-Request-Id"
request-id-header: "X-Request-Id"
# Bool. Enable OpenTelemetry based tracing support.
# Default: false
tracing-enabled: false
# String. Set the transport protocol for the tracing system. Can either be "grpc"
# for OTLP gRPC, or "http" for OTLP HTTP.
# Options: ["grpc", "http"]
# Default: "grpc"
tracing-transport: "grpc"
# String. Endpoint of the trace ingester. When using the gRPC or HTTP based
# transports, provide the endpoint as a single address/port combination without a
# protocol scheme.
# Examples: ["localhost:4317"]
# Default: ""
tracing-endpoint: ""
# Bool. Disable TLS for the gRPC and HTTP transport protocols.
# Default: false
tracing-insecure-transport: false
# Bool. Enable OpenTelemetry based metrics support.
# Default: false
metrics-enabled: false
# Bool. Enable HTTP Basic Authentication for Prometheus metrics endpoint.
# Default: false
metrics-auth-enabled: false
# String. Username for Prometheus metrics endpoint.
# Default: ""
metrics-auth-username: ""
# String. Password for Prometheus metrics endpoint.
# Default: ""
metrics-auth-password: ""
```

View file

@ -0,0 +1,63 @@
# Observability and Metrics
These settings let you tune and configure certain observability related behaviours.
GoToSocial uses OpenTelemetry. The metrics and trace exporters can be configured using the standard OpenTelemetry SDK environment variables. For a full reference, see [the OpenTelemetry docs](https://opentelemetry.io/docs/languages/sdk-configuration/).
## Metrics
Before enabling metrics, [read the guide](../advanced/metrics.md) and ensure you've taken the appropriate security measures for your setup.
If you want to expose metrics with (basic) authentication, you'll need to do this with a reverse proxy.
For more information and examples, see the [GtS metrics documentation](https://docs.gotosocial.org/en/latest/advanced/metrics/).
## Settings
```yaml
##############################################
##### OBSERVABILITY AND METRICS SETTINGS #####
##############################################
# String. Header name to use to extract a request or
# trace ID from. Typically set by a loadbalancer or proxy.
#
# Default: "X-Request-Id"
request-id-header: "X-Request-Id"
# Bool. Enable OpenTelemetry based tracing support.
#
# When enabling tracing, you must also configure a traces
# exporter using the OTEL environment variable documented here:
#
# https://opentelemetry.io/docs/languages/sdk-configuration/general/#otel_traces_exporter
#
# Default: false
tracing-enabled: false
# Bool. Enable OpenTelemetry based metrics support.
#
# To expose Prometheus metrics, you must configure a metrics producer and
# a metrics exporter, using the OTEL environment variables documented here:
#
# https://pkg.go.dev/go.opentelemetry.io/contrib/exporters/autoexport#NewMetricReader
#
# Typically, you will want to set the following environment variables
# (take note of the plural "producers" and singular "exporter"):
#
# - OTEL_METRICS_PRODUCERS=prometheus
# - OTEL_METRICS_EXPORTER=prometheus
#
# With these variables set, a Prometheus metrics endpoint will be exposed at
# localhost:9464/metrics. This can be further configured using the variables:
#
# - OTEL_EXPORTER_PROMETHEUS_HOST
# - OTEL_EXPORTER_PROMETHEUS_PORT
#
# For more information, see the GtS metrics documentation here:
#
# https://docs.gotosocial.org/en/latest/advanced/metrics/
#
# Default: false
metrics-enabled: false
```

View file

@ -20,6 +20,9 @@ To validate your configuration, you can use the "Administration -> Actions -> Em
!!! info
For safety reasons, the smtp library used by GoToSocial will refuse to send authentication credentials over an unencrypted connection, unless the mail provider is running on localhost.
!!! info
If your SMTP server offers `STARTTLS` in its EHLO response GoToSocial will try to use it. The SMTP server must hence also have valid SSL certificates. If you're sending mail via localhost and don't want to set up certificates make sure that your SMTP server doesn't announce STARTTLS support. In postfix this can be done via `-o smtpd_tls_security_level=none`.
## Settings
The configuration options for smtp are as follows:

View file

@ -35,4 +35,14 @@ statuses-poll-option-max-chars: 50
# Examples: [4, 6, 10]
# Default: 6
statuses-media-max-files: 6
# Int. Maximum number of statuses a user can schedule at time.
# Examples: [300]
# Default: 300
scheduled-statuses-max-total: 300
# Int. Maximum number of statuses a user can schedule for a single day.
# Examples: [25]
# Default: 25
scheduled-statuses-max-daily: 25
```

View file

@ -101,6 +101,20 @@ storage-s3-secret-key: ""
# Default: ""
storage-s3-bucket: ""
# String. Key prefix to use for the S3 storage.
# This is optional.
#
# Prefix must end with a trailing slash.
#
# This is useful if you want to store multiple instances in the same bucket,
# or if you want to store your data in a subdirectory of the bucket.
# This has no effect if the storage backend isn't "s3".
#
# Examples: ["gts-instance1/", "gts-instance2/"]
# Default: ""
storage-s3-key-prefix: ""
# String. Bucket lookup type.
#
# If you know what kind of bucket lookup type you need you can specify it here.

View file

@ -2,11 +2,14 @@
To correctly enforce [rate limiting](../api/ratelimiting.md), GoToSocial relies on the concept of "trusted proxies" in order to accurately determine the IP address of clients accessing your server.
A "trusted proxy" is an intermediate network hop that GoToSocial can be instructed to trust to provide a correct client IP address.
A "trusted proxy" is an intermediate network hop that GoToSocial can be instructed to trust to provide a correct client IP address via an `X-Forwarded-For` or `X-Real-IP` header.
For example, if you are running in a reverse proxy configuration with Docker + Nginx, then the Docker network address of Nginx should be configured as a trusted proxy, since all traffic from the wider internet will come into GoToSocial via Nginx.
Without setting `trusted-proxies` correctly, GoToSocial will see all incoming client IP addresses as the same address, which leads to rate limiting issues, since GoToSocial uses client IP addresses to bucket rate limits.
If `trusted-proxies` is not set correctly, GoToSocial will see all incoming client IP addresses as the same address. This will lead to rate limiting issues, since GoToSocial uses client IP addresses to bucket rate limits.
!!! tip
If you reached this page via the trusted proxies warning on a GoToSocial page, and the suggested address to add is `127.0.0.1`, then before you try any of the other troubleshooting steps, ensure that your reverse proxy is configured to correctly pass either `X-Forwarded-For` or `X-Real-IP`.
## tl;dr: How to set `trusted-proxies` correctly

View file

@ -38,4 +38,4 @@ We introduced a sign-up flow in v0.16.0. The server you want to sign up to must
## Why's it still in Beta?
Take a look at the [list of open bugs](https://codeberg.org/superseriousbusiness/gotosocial/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and the [roadmap](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/ROADMAP.md) for a more detailed rundown.
Take a look at the [list of open bugs](https://codeberg.org/superseriousbusiness/gotosocial/issues?labels=378161) and the [roadmap](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/ROADMAP.md) for a more detailed rundown.

View file

@ -248,6 +248,90 @@ Another difference between GoToSocial and other server implementations is that G
Instead, to build a view of a GoToSocial user's pinned posts, it is recommended that remote instances simply poll a GoToSocial Actor's `featured` collection every so often, and add/remove posts in their cached representation as appropriate.
## `hidesToPublicFromUnauthedWeb` and `hidesCcPublicFromUnauthedWeb`
GoToSocial uses the properties `hidesToPublicFromUnauthedWeb` and `hidesCcPublicFromUnauthedWeb` to indicate whether an actor prefers to hide posts addressed `to` or `cc` public from unauthenticated (ie., logged-out) visitors to web pages, web apps, and web APIs.
Some background for this: many ActivityPub server softwares allow unauthenticated visitors to the profile web page of an actor to see a list of posts that an actor has created that are addressed either `to` or `cc` public. These are often called "public" posts, and "unlisted", "unlocked", or "quiet public" posts, respectively. GoToSocial provides [a settings flag](../user_guide/settings.md#visibility-level-of-posts-to-show-on-your-profile) that allows GtS accounts to hide posts from the web view of their profile, as one layer of protection to make it more of a nuisance to scrape/stalk someone with a GtS account.
While this setting works for hiding posts of an actor *on their own instance*, prior to GoToSocial v0.20.0, this preference was not federated out to other instances, nor was it federated in from other instances. This leads to two problems:
1. Many other fedi server softwares permit logged-out visitors, via a web app, to look up profiles of *remote* accounts, and to see public and unlisted posts created by those accounts. This means that it is trivial to work around the ability of GtS users to hide their posts from the web. For example, say a GtS user at `@someone@gts.example.org` locks down their profile by setting the visibility of posts on their profile to "none"; this prevents visitors to `gts.example.org` from seeing posts, but one could visit eg. `mastodon.example.org` and, while logged out, look up `@someone@gts.example.org`, and see all the posts there that have been sent to, or dereferenced by, actors on `mastodon.example.org`. This makes the GtS user's choice to hide their posts significantly less meaningful.
2. In an effort to support this extra layer of privacy, by default GoToSocial instances do not show posts from remote instances unless they are addressed `to` public. For example, if someone from `mastodon.example.org` were to reply to a post by `@someone@gts.example.org`, and the reply was only addressed `cc` public instead of `to` public, the GtS instance `gts.example.org` would *not* show that reply in the web view, as it could not determine the preferences of the user from `mastodon.example.org` with regard to showing the "quiet public" post to logged-out visitors to the web page. This could be frustrating for the GtS user, as they might want to show a more complete picture of the thread that they started, right there on their instance; this could also frustrate the Mastodon user, as are used to their "quiet public" posts being visible on the web even when logged out.
The actor properties `hidesToPublicFromUnauthedWeb` and `hidesCcPublicFromUnauthedWeb` are a move towards solving these issues, by allowing actors to signal their preferences for hiding or showing `to`- and/or `cc`-public posts to unauthenticated visitors via the web.
For example, the following actor representation indicates that the actor is happy to show both "unlisted" and "public" posts via unauthed web view (this represents the de-facto default for actors on Mastodon and most other server softwares):
```json
{
"@context": [
"https://gotosocial.org/ns",
"https://www.w3.org/ns/activitystreams"
],
"type": "Person",
[... other properties here ...]
"hidesToPublicFromUnauthedWeb": false,
"hidesCcPublicFromUnauthedWeb": false,
[... other properties here ...]
}
```
By contrast, the following indicates that the actor hides "unlisted" posts but is happy to show "public" posts unauthed (this is the default for actors on GtS instances):
```json
{
"@context": [
"https://gotosocial.org/ns",
"https://www.w3.org/ns/activitystreams"
],
"type": "Person",
[... other properties here ...]
"hidesToPublicFromUnauthedWeb": false,
"hidesCcPublicFromUnauthedWeb": true,
[... other properties here ...]
}
```
And the following shows that the actor wants to show no posts unauthed at all:
```json
{
"@context": [
"https://gotosocial.org/ns",
"https://www.w3.org/ns/activitystreams"
],
"type": "Person",
[... other properties here ...]
"hidesToPublicFromUnauthedWeb": true,
"hidesCcPublicFromUnauthedWeb": true,
[... other properties here ...]
}
```
Both `hidesToPublicFromUnauthedWeb` and `hidesCcPublicFromUnauthedWeb` are defined in [the GoToSocial json-ld `@context` document](https://gotosocial.org/ns).
In line with its emphasis on having people opt-in to greater visibility rather than opt-out, when receiving a post from a remote actor that does not set these flags, GoToSocial assumes `hidesToPublicFromUnauthedWeb` = `false`, and `hidesCcPublicFromUnauthedWeb` = `true`. That is, the pre-v0.20.x behavior of GoToSocial is still the default for remote servers that don't (yet) use these flags.
!!! note
While unusual, it's possible for an actor to also specify that they want to show "unlisted" posts but hide "public" ones:
```json
{
"@context": [
"https://gotosocial.org/ns",
"https://www.w3.org/ns/activitystreams"
],
"type": "Person",
[... other properties here ...]
"hidesToPublicFromUnauthedWeb": true,
"hidesCcPublicFromUnauthedWeb": false,
[... other properties here ...]
}
```
GoToSocial respects these flags for incoming posts, but it does not let accounts set this combination of flags for outgoing posts. It may be desirable for other implementers to also prevent users from being able to set this state, as it doesn't make a lot of sense.
## Actor Migration / Aliasing
GoToSocial supports account migration from one instance/server to another through a combination of the `Move` activity, and the Actor Object properties `alsoKnownAs` and `movedTo`.

View file

@ -1,5 +1,8 @@
# Interaction Policy
!!! warning "Feature still in development"
Much like GoToSocial, this feature is still in pre-v1 beta development. Naming or schemas or methods of approval / rejection may change. We aim to finalize the document by GoToSocial v0.21.0, at which point it can be considered "ready" for other ActivityPub implementers to use.
GoToSocial uses the property `interactionPolicy` on posts, in order to indicate to remote instances what sort of interactions are (conditionally) permitted to be processed and stored by the origin server, for any given post.
The `@context` document for `interactionPolicy` and related objects and properties is at `https://gotosocial.org/ns`.
@ -15,6 +18,9 @@ The `@context` document for `interactionPolicy` and related objects and properti
For better or worse, GoToSocial can offer only a best-effort, partial, technological solution to what is more or less an issue of social behavior and boundaries.
!!! info "Deprecated `always` and `approvalRequired` properties"
Previous versions of this document used the properties `always` and `approvalRequired`. These are now deprecated in favor of `automaticApproval` and `manualApproval`. GoToSocial versions before v0.20.0 send and receive only these deprecated properties. GoToSocial v0.20.0 sends and receives both the deprecated and the new properties. GoToSocial v0.21.0 onwards uses only the new properties.
## Overview
`interactionPolicy` is an object property attached to the post-like `Object`s `Note`, `Article`, `Question`, etc, with the following format:
@ -28,16 +34,16 @@ The `@context` document for `interactionPolicy` and related objects and properti
[...],
"interactionPolicy": {
"canLike": {
"always": [ "zero_or_more_uris_that_can_always_do_this" ],
"approvalRequired": [ "zero_or_more_uris_that_require_approval_to_do_this" ]
"automaticApproval": [ "zero_or_more_uris_that_can_always_do_this" ],
"manualApproval": [ "zero_or_more_uris_that_require_approval_to_do_this" ]
},
"canReply": {
"always": [ "zero_or_more_uris_that_can_always_do_this" ],
"approvalRequired": [ "zero_or_more_uris_that_require_approval_to_do_this" ]
"automaticApproval": [ "zero_or_more_uris_that_can_always_do_this" ],
"manualApproval": [ "zero_or_more_uris_that_require_approval_to_do_this" ]
},
"canAnnounce": {
"always": [ "zero_or_more_uris_that_can_always_do_this" ],
"approvalRequired": [ "zero_or_more_uris_that_require_approval_to_do_this" ]
"automaticApproval": [ "zero_or_more_uris_that_can_always_do_this" ],
"manualApproval": [ "zero_or_more_uris_that_require_approval_to_do_this" ]
}
},
[...]
@ -52,10 +58,10 @@ In the `interactionPolicy` object:
And:
- `always` denotes ActivityPub URIs/IDs of `Actor`s or `Collection`s of `Actor`s who are permitted to create + distribute an interaction targeting a post without requiring manual approval by the post author.
- `approvalRequired` denotes ActivityPub URIs/IDs of `Actor`s or `Collection`s of `Actor`s who are permitted to create an interaction targeting a post, but should wait for manual approval by the post author before distributing it (see [Requesting, Obtaining, and Validating Approval](#requesting-obtaining-and-validating-approval)).
- `automaticApproval` denotes ActivityPub URIs/IDs of `Actor`s or `Collection`s of `Actor`s who will receive automated approval from the post author to create + distribute an interaction targeting a post.
- `manualApproval` denotes ActivityPub URIs/IDs of `Actor`s or `Collection`s of `Actor`s who will receive approval from the post author at the author's own discretion, and may not receive approval at all, or may be rejected (see [Requesting, Obtaining, and Validating Approval](#requesting-obtaining-and-validating-approval)).
Valid URI entries in `always` and `approvalRequired` include:
Valid URI entries in `automaticApproval` and `manualApproval` include:
- the magic ActivityStreams Public URI `https://www.w3.org/ns/activitystreams#Public`
- the URIs of the post creator's `Following` and/or `Followers` collections
@ -74,21 +80,21 @@ For example:
```
!!! info
Be aware that according to JSON-LD the values of `always` and `approvalRequired` can be either single strings or arrays of strings. That is, the following are all valid:
Be aware that according to JSON-LD the values of `automaticApproval` and `manualApproval` can be either single strings or arrays of strings. That is, the following are all valid:
- Single string: `"always": "https://example.org/users/someone"`
- Single-entry array: `"always": [ "https://example.org/users/someone" ]`
- Multiple-entry array: `"always": [ "https://example.org/users/someone", "https://example.org/users/someone_else" ]`
- Single string: `"automaticApproval": "https://example.org/users/someone"`
- Single-entry array: `"automaticApproval": [ "https://example.org/users/someone" ]`
- Multiple-entry array: `"automaticApproval": [ "https://example.org/users/someone", "https://example.org/users/someone_else" ]`
## Specifying Nobody
To specify that **nobody** can perform an interaction on a post **except** for its author (who is always permitted), implementations should set the `always` array to **just the URI of the post author**, and `approvalRequired` can be unset, `null`, or empty.
To specify that **nobody** can perform an interaction on a post **except** for its author (who is always permitted), implementations should set the `automaticApproval` array to **just the URI of the post author**, and `manualApproval` can be unset, `null`, or empty.
For example, the following `canLike` value indicates that nobody can `Like` the post it is attached to except for the post author:
```json
"canLike": {
"always": "the_activitypub_uri_of_the_post_author"
"automaticApproval": "the_activitypub_uri_of_the_post_author"
},
```
@ -103,13 +109,13 @@ Another example. The following `interactionPolicy` on a post by `https://example
[...],
"interactionPolicy": {
"canLike": {
"always": "https://www.w3.org/ns/activitystreams#Public"
"automaticApproval": "https://www.w3.org/ns/activitystreams#Public"
},
"canReply": {
"always": "https://example.org/users/someone"
"automaticApproval": "https://example.org/users/someone"
},
"canAnnounce": {
"always": "https://example.org/users/someone"
"automaticApproval": "https://example.org/users/someone"
}
},
[...]
@ -128,28 +134,28 @@ For example:
```json
[...],
"canReply": {
"always": "https://example.org/users/someone",
"approvalRequired": "https://www.w3.org/ns/activitystreams#Public"
"automaticApproval": "https://example.org/users/someone",
"manualApproval": "https://www.w3.org/ns/activitystreams#Public"
},
[...]
```
Here, `@someone@example.org` is present in `always`, and is also implicitly present in the magic ActivityStreams Public collection in `approvalRequired`. In this case, they can always reply, as the `always` value is more explicit.
Here, `@someone@example.org` is present in `automaticApproval`, and is also implicitly present in the magic ActivityStreams Public collection in `manualApproval`. In this case, they can always reply, as the `automaticApproval` value is more explicit.
Another example:
```json
[...],
"canReply": {
"always": "https://www.w3.org/ns/activitystreams#Public",
"approvalRequired": "https://example.org/users/someone"
"automaticApproval": "https://www.w3.org/ns/activitystreams#Public",
"manualApproval": "https://example.org/users/someone"
},
[...]
```
Here, `@someone@example.org` is present in `approvalRequired`, but is also implicitly present in the magic ActivityStreams Public collection in `always`. In this case everyone can reply without approval, **except** for `@someone@example.org`, who requires approval.
Here, `@someone@example.org` is present in `manualApproval`, but is also implicitly present in the magic ActivityStreams Public collection in `automaticApproval`. In this case everyone can reply without approval, **except** for `@someone@example.org`, who requires approval.
In case the **exact same** URI is present in both `always` and `approvalRequired`, the **highest level of permission** takes precedence (ie., a URI in `always` takes precedence over the same URI in `approvalRequired`).
In case the **exact same** URI is present in both `automaticApproval` and `manualApproval`, the **highest level of permission** takes precedence (ie., a URI in `automaticApproval` takes precedence over the same URI in `manualApproval`).
## Default / fallback `interactionPolicy`
@ -164,20 +170,20 @@ When the `interactionPolicy` property is not present at all on a post, or the `i
[...],
"interactionPolicy": {
"canLike": {
"always": "https://www.w3.org/ns/activitystreams#Public"
"automaticApproval": "https://www.w3.org/ns/activitystreams#Public"
},
"canReply": {
"always": "https://www.w3.org/ns/activitystreams#Public"
"automaticApproval": "https://www.w3.org/ns/activitystreams#Public"
},
"canAnnounce": {
"always": "https://www.w3.org/ns/activitystreams#Public"
"automaticApproval": "https://www.w3.org/ns/activitystreams#Public"
}
},
[...]
}
```
As implied by the lack of any `approvalRequired` property in any of the sub-policies, the default value for `approvalRequired` is an empty array.
As implied by the lack of any `manualApproval` property in any of the sub-policies, the default value for `manualApproval` is an empty array.
This default `interactionPolicy` was designed to reflect the de facto interaction policy of all posts from pre-v0.17.0 GoToSocial, and other ActivityPub server softwares, at the time of writing. That is to say, it is exactly what servers that are not interaction policy aware *already assume* about interaction permissions.
@ -200,7 +206,7 @@ If `canLike` is missing on an `interactionPolicy`, or the value of `canLike` is
```json
"canLike": {
"always": "https://www.w3.org/ns/activitystreams#Public"
"automaticApproval": "https://www.w3.org/ns/activitystreams#Public"
}
```
@ -212,7 +218,7 @@ If `canReply` is missing on an `interactionPolicy`, or the value of `canReply` i
```json
"canReply": {
"always": "https://www.w3.org/ns/activitystreams#Public"
"automaticApproval": "https://www.w3.org/ns/activitystreams#Public"
}
```
@ -224,7 +230,7 @@ If `canAnnounce` is missing on an `interactionPolicy`, or the value of `canAnnou
```json
"canAnnounce": {
"always": "https://www.w3.org/ns/activitystreams#Public"
"automaticApproval": "https://www.w3.org/ns/activitystreams#Public"
}
```
@ -266,7 +272,7 @@ Likewise, when enforcing received interaction policies, GoToSocial will **ALWAYS
As such, when sending out interaction policies, GoToSocial will **ALWAYS** add the URI of the post author to the `canLike.always`, `canReply.always`, and `canAnnounce.always` arrays, **UNLESS** they are already covered by the ActivityStreams magic public URI.
Likewise, when enforcing received interaction policies, GoToSocial will **ALWAYS** behave as though the URI of the post author themself is present in each `always` field, even if it wasn't.
Likewise, when enforcing received interaction policies, GoToSocial will **ALWAYS** behave as though the URI of the post author themself is present in each `automaticApproval` field, even if it wasn't.
## Examples
@ -293,18 +299,18 @@ This can be achieved with the following `interactionPolicy`, which is attached t
[...],
"interactionPolicy": {
"canLike": {
"always": "https://www.w3.org/ns/activitystreams#Public"
"automaticApproval": "https://www.w3.org/ns/activitystreams#Public"
},
"canReply": {
"always": [
"automaticApproval": [
"https://example.org/users/the_mighty_zork",
"https://example.org/users/booblover6969",
"https://example.org/users/hodor"
],
"approvalRequired": "https://www.w3.org/ns/activitystreams#Public"
"manualApproval": "https://www.w3.org/ns/activitystreams#Public"
},
"canAnnounce": {
"always": [
"automaticApproval": [
"https://example.org/users/the_mighty_zork",
"https://example.org/users/the_mighty_zork/followers",
"https://example.org/users/booblover6969",
@ -333,13 +339,13 @@ This can be achieved by setting the following `interactionPolicy` on every post
[...],
"interactionPolicy": {
"canLike": {
"always": "https://www.w3.org/ns/activitystreams#Public"
"automaticApproval": "https://www.w3.org/ns/activitystreams#Public"
},
"canReply": {
"always": "https://example.org/users/the_mighty_zork"
"automaticApproval": "https://example.org/users/the_mighty_zork"
},
"canAnnounce": {
"always": "https://www.w3.org/ns/activitystreams#Public"
"automaticApproval": "https://www.w3.org/ns/activitystreams#Public"
}
},
[...]
@ -361,13 +367,13 @@ In this example, `@the_mighty_zork` wants to write a completely open post that c
[...],
"interactionPolicy": {
"canLike": {
"always": "https://www.w3.org/ns/activitystreams#Public"
"automaticApproval": "https://www.w3.org/ns/activitystreams#Public"
},
"canReply": {
"always": "https://www.w3.org/ns/activitystreams#Public"
"automaticApproval": "https://www.w3.org/ns/activitystreams#Public"
},
"canAnnounce": {
"always": "https://www.w3.org/ns/activitystreams#Public"
"automaticApproval": "https://www.w3.org/ns/activitystreams#Public"
}
},
[...]
@ -416,7 +422,7 @@ This section describes the enforcement and verification of interaction policies,
### Requesting, Obtaining, and Validating Approval
When an actor's URI is in the `approvalRequired` array for a type of interaction, **or** their presence in a collection needs to be validated (see [Validating presence in a Followers / Following collection](#validating-presence-in-a-followers--following-collection)), implementations wishing to obtain approval for that actor to interact with a policied post should do the following:
When an actor's URI is in the `manualApproval` array for a type of interaction, **or** their presence in a collection needs to be validated (see [Validating presence in a Followers / Following collection](#validating-presence-in-a-followers--following-collection)), implementations wishing to obtain approval for that actor to interact with a policied post should do the following:
1. Compose the interaction `Activity` (ie., `Like`, `Create` (reply), or `Announce`), as normal.
2. Address the `Activity` `to` and `cc` the expected recipients for that `Activity`, as normal.
@ -592,11 +598,11 @@ If the approval cannot be dereferenced, or does not pass validity checks, the in
### Validating presence in a Followers / Following collection
If an `Actor` interacting with an `object` (via `Like`, `inReplyTo`, or `Announce`) is permitted to do that interaction based on their presence in a `Followers` or `Following` collection in the `always` field of an interaction policy, then their server **should still wait** for an `Accept` to be received from the server of the target actor, before distributing the interaction more widely with the `approvedBy` property set to the URI/ID of the approval.
If an `Actor` interacting with an `object` (via `Like`, `inReplyTo`, or `Announce`) is permitted to do that interaction based on their presence in a `Followers` or `Following` collection in the `automaticApproval` field of an interaction policy, then their server **should still wait** for an `Accept` to be received from the server of the target actor, before distributing the interaction more widely with the `approvedBy` property set to the URI/ID of the approval.
This is to prevent scenarios where third servers have to somehow verify the presence of the interacting `Actor` in the `Followers` or `Following` collection of the `Actor` being interacted with. It is simpler to allow the target server to do that verification, and to trust that their approval implicitly agrees that the interacting `Actor` is present in the relevant collection.
Likewise, when receiving an interaction from an `Actor` whose permission to interact matches with one of the `Following` or `Followers` collections in the `always` property, the server of the interacted-with `Actor` should ensure that they *always* send out an `Accept` as soon as possible, so that the interacting `Actor` server can send out the `Activity` with the proper proof of acceptance.
Likewise, when receiving an interaction from an `Actor` whose permission to interact matches with one of the `Following` or `Followers` collections in the `automaticApproval` property, the server of the interacted-with `Actor` should ensure that they *always* send out an `Accept` as soon as possible, so that the interacting `Actor` server can send out the `Activity` with the proper proof of acceptance.
This process should bypass the normal "pending approval" stage whereby the server of the `Actor` being interacted with notifies them of the pending interaction, and waits for them to accept or reject, since there is no point notifying an `Actor` of a pending approval that they have already explicitly agreed to. In the GoToSocial codebase in particular, this is called "preapproval".
@ -606,7 +612,7 @@ This section describes optional behaviors that implementers *may* use when sendi
#### Always send out `Accept`s
Implementers may wish to *always* send out an `Accept` to remote interacters, even when the interaction is implicitly or explicitly permitted by their presence in the `always` array. When receiving such an `Accept`, implementations may still want to update their representation of the interaction to include an `approvedBy` URI pointing at an approval. This may be useful later on when handling revocations (TODO).
Implementers may wish to *always* send out an `Accept` to remote interacters, even when the interaction is implicitly or explicitly permitted by their presence in the `automaticApproval` array. When receiving such an `Accept`, implementations may still want to update their representation of the interaction to include an `approvedBy` URI pointing at an approval. This may be useful later on when handling revocations (TODO).
#### Type hinting: inline `object` property on `Accept` and `Reject`

View file

@ -1,5 +1,56 @@
# Posts and Post Properties
## Attachments, Blurhash, and Focal Point
GoToSocial sends media attachments in the `attachment` property of posts using the following types:
- `Image` - any image type (webp, jpeg, gif, png, etc).
- `Video` - any video type (mp4, mkv, webm, etc).
- `Audio` - any audio type (mp3, flac, wma, etc).
- `Document` - fallback for any other / unknown type.
Attachments sent from GoToSocial include the MIME `mediaType`, the `url` of the full-sized version of the media file, and the `summary` property, which can be interpreted by remote instance's as a short description / alt text for the attachment.
Types `Image` and `Video` will also include the `http://joinmastodon.org/ns#blurhash` property so that remotes can generate a colorful hash of the image. If an audio file included an embedded cover art image, then the `Audio` type will also include a blurhash. See the [Mastodon blurhash docs](https://docs.joinmastodon.org/spec/activitypub/#blurhash).
`Image` types may also include the `http://joinmastodon.org/ns#focalPoint` property, which will be an array of two floats between -1.0 and 1.0 indicating the x-y coordinates of the image's focal point. See the [Mastondon focalPoint docs](https://docs.joinmastodon.org/spec/activitypub/#focalPoint).
Here's an example of a `Note` with one attachment:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
{
"blurhash": "toot:blurhash",
"focalPoint": {
"@container": "@list",
"@id": "toot:focalPoint"
},
"toot": "http://joinmastodon.org/ns#"
}
],
"type": "Note",
[...],
"attachment": [
{
"blurhash": "LIIE|gRj00WB-;j[t7j[4nWBj[Rj",
"focalPoint": [
-0.5,
0.5
],
"mediaType": "image/jpeg",
"summary": "Black and white image of some 50's style text saying: Welcome On Board",
"type": "Image",
"url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg"
}
],
[...]
}
```
When receiving posts with attachments from remote instances, it will try to parse any of the four types `Image`, `Video`, `Audio`, or `Document` into media attachments. It doesn't matter which type is used. It will check for `blurhash` and `focalPoint` properties and use these if they are set. It will use the `summary` value as a short description / alt text, falling back to `name` if `summary` is not set.
## Hashtags
GoToSocial users can include hashtags in their posts, which indicate to other instances that that user wishes their post to be grouped together with other posts using the same hashtag, for discovery purposes.

View file

@ -55,7 +55,7 @@ For media storage, including [storage of remote media files in the cache](../adm
### Single-board Computers
GoToSocial's light system requirements means that it runs pretty well on decently-specced single-board computers. If running on a single-board computer, you should ensure that GoToSocial is using a USB drive (preferably an SSD) to store its database files and media, not SD card storage, since the latter tends to be too slow to run a database on.
GoToSocial's light system requirements means that it runs pretty well on decently-specced single-board computers. If running on a single-board computer, you should ensure that GoToSocial is using a USB drive (preferably an SSD) to store its database files and media, not SD card storage, since the latter tends to be too slow to run a database on and can easily get corrupted with write-heavy workloads.
### VPS

View file

@ -63,8 +63,6 @@ You'll probably need to change the following settings:
- Set `host` to whatever hostname you're going to be running the server on (eg., `example.org`).
- Set `port` to `443`.
- Set `db-type` to `sqlite`.
- Set `db-address` to `sqlite.db`.
- Set `storage-local-base-path` to the storage directory you created above (eg., `/gotosocial/storage`).
- Set `letsencrypt-enabled` to `true`.
- Set `letsencrypt-cert-dir` to the certificate storage directory you created above (eg., `/gotosocial/storage/certs`).

View file

@ -10,6 +10,6 @@ GoToSocial 在主域名上提供一个 `robots.txt` 文件。该文件包含试
AI 爬虫来自一个[社区维护的仓库][airobots]。目前是手动保持同步的。如果你知道有任何遗漏的爬虫,请给他们提交一个 PR
众所周知,很多 AI 爬虫在 `robots.txt` 不允许其 User-Agent 的情况下,仍然会忽略对应规则并继续抓去内容。这意味着 `robots.txt` 文件并不是确保 AI 爬虫不抓取你的内容的万无一失的方法。除此以外,你可能还需要考虑通过[请求标头过滤](request_filtering_modes.md)来阻止对应 User-Agent,以及启用基于工作证明的[爬虫防护](../advanced/scraper_deterrence.md)
众所周知,很多 AI 爬虫在 `robots.txt` 不允许其 User-Agent 的情况下,仍然会忽略对应规则并继续抓去内容。这意味着 `robots.txt` 文件并不是确保 AI 爬虫不抓取你的内容的万无一失的方法。除此以外,你可能还需要考虑通过[请求标头过滤](request_filtering_modes.md)来阻止对应 User-Agent。
[airobots]: https://github.com/ai-robots-txt/ai.robots.txt/

View file

@ -54,4 +54,4 @@ location /metrics {
[otel]: https://opentelemetry.io/
[prom]: https://prometheus.io/docs/instrumenting/exposition_formats/
[obs]: ../configuration/observability.md
[obs]: ../configuration/observability_and_metrics.md

View file

@ -1,18 +0,0 @@
# 爬虫防护
GoToSocial 提供一个可选的、基于工作量证明的爬虫和自动化 HTTP 客户端防护机制,可在账户页和贴文页的网页视图上启用。
它的工作原理是:针对每个传入的 HTTP 请求,系统会根据客户端信息和当前时间生成一个唯一质询(一个十六进制编码的 SHA256 哈希值)。然后,它要求客户端为该质询的一部分找到一个附加值,使(附加值+质询部分)组合计算出的新 SHA256 哈希值(同样为十六进制编码)至少包含 4 个前导 '0' 字符。这个质询会通过一个极简的等待页面呈现给客户端,该页面包含一个独立的 JavaScript worker 来计算解决方案。
一旦客户端提供了此质询的解并通过在查询参数中携带该方案刷新页面GoToSocial 将验证此方案。验证成功后,服务端会返回用户期望访问的账户或贴文页面,并设置一个 Cookie。该 Cookie 允许用户在接下来最多一小时内免验证访问该实例。
启用此功能的目的是让自动化数据收集(例如 AI 公司、搜索引擎)对你实例的账户和贴文页面进行爬取的行为,在经济上变得不可行。唯一的缺点是,用户需要启用 JavaScript 才能访问你的账户和贴文网页视图。
这个功能深受优秀的 [anubis] 项目的启发,但我们最终决定自己实现,只包含我们需要的功能,使用最少的代码,并能与我们现有的授权/认证流程实现更细粒度的结合。
GoToSocial 实现的这个爬虫防护功能仍然是极其精简的。因此,如果你需要更多功能或对防护措施进行更精细的控制,那么完全可以禁用我们的内置功能,并在你的实例前部署像 [anubis] 这样的服务!
!!! warning "警告"
这个基于工作量证明的爬虫防护机制并不保护用户账户页的 RSS feed因为这会带来额外的复杂性。如果你需要确保 RSS feed 可被访问,那么在这种情况下,[anubis] 可能是更合适的选择!
[anubis]: https://github.com/TecharoHQ/anubis

View file

@ -16,7 +16,7 @@ tracing-insecure-transport: true
```
[otel]: https://opentelemetry.io/
[obs]: ../configuration/observability.md
[obs]: ../configuration/observability_and_metrics.md
[tempo]: https://grafana.com/oss/tempo/
[grafana]: https://grafana.com/oss/grafana/
[ext]: https://codeberg.org/superseriousbusiness/gotosocial/tree/main/example/tracing

View file

@ -149,21 +149,4 @@ advanced-csp-extra-uris: []
# 选项: ["block", "allow", ""]
# 默认: ""
advanced-header-filter-mode: ""
# 布尔值。启用基于工作量证明的爬虫威慑机制,
# 作用于账户页和贴文页面。这将为每个 HTTP 客户端生成一个唯一确定
# 的质询,需要由客户端在访问上述端点时完成。
# 完成后,客户端会获得一个 Cookie允许其在 1 小时窗口内免验证访问。
#
# 这样做的结果是,它理论上使得对这些端点的抓取在经济上变得不可行,
# 同时对你自己的实例的性能影响可以忽略不计。
#
# 缺点是它要求客户端启用 JavaScript。
#
# 更多详情请查阅文档:
# https://docs.gotosocial.org/zh-cn/latest/admin/scraper_deterrence
#
# 选项: [true, false]
# 默认值: true
advanced-scraper-deterrence: false
```

View file

@ -38,4 +38,4 @@ GoToSocial 默认配置了基于 IP 的[限流规则](./api/ratelimiting.md)
## 为什么还在 Beta 阶段?
查看[当前 bug 列表](https://codeberg.org/superseriousbusiness/gotosocial/issues?q=is%3Aissue+is%3Aopen+label%3Abug)和[路线图](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/docs/locales/zh/repo/ROADMAP.md)以获取更详细的信息。
查看[当前 bug 列表](https://codeberg.org/superseriousbusiness/gotosocial/issues?labels=378161)和[路线图](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/docs/locales/zh/repo/ROADMAP.md)以获取更详细的信息。

View file

@ -62,7 +62,7 @@ nav:
- "configuration/syslog.md"
- "configuration/httpclient.md"
- "configuration/advanced.md"
- "configuration/observability.md"
- "configuration/observability_and_metrics.md"
- "进阶":
- "概述": "advanced/index.md"
- "advanced/host-account-domain.md"
@ -80,7 +80,6 @@ nav:
- "advanced/tracing.md"
- "advanced/metrics.md"
- "advanced/replicating-sqlite.md"
- "advanced/scraper_deterrence.md"
- "advanced/sqlite-networked-storage.md"
- "适用进阶场景的构建":
- "advanced/builds/nowasm.md"

View file

@ -272,9 +272,9 @@ GoToSocial 支持 [OpenID Connect (OIDC)](https://openid.net/connect/) 身份提
## 已知问题
由于 GoToSocial 仍处于测试阶段,存在很多错误。我们使用 [Codeberg issues](https://codeberg.org/superseriousbusiness/gotosocial/issues?q=is%3Aissue+is%3Aopen+label%3Abug) 跟踪这些问题。
由于 GoToSocial 仍处于测试阶段,存在很多错误。我们使用 [Codeberg issues](https://codeberg.org/superseriousbusiness/gotosocial/issues?labels=378161) 跟踪这些问题。
由于每个 ActivityPub 服务端实现对协议的解释略有不同,有些服务端尚未与 GoToSocial 正常联合。我们在 [这个项目](https://codeberg.org/superseriousbusiness/gotosocial/projects/4) 中跟踪这些问题。最终,我们希望确保任何可以与 Mastodon 正确联合的 ActivityPub 实现也能够与 GoToSocial 联合。
由于每个 ActivityPub 服务端实现对协议的解释略有不同,有些服务端尚未与 GoToSocial 正常联合。我们在 [这个项目](https://codeberg.org/superseriousbusiness/gotosocial/issues?labels=378188) 中跟踪这些问题。最终,我们希望确保任何可以与 Mastodon 正确联合的 ActivityPub 实现也能够与 GoToSocial 联合。
---

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View file

@ -41,6 +41,7 @@
// - read:applications: grants read access to user-managed applications
// - read:blocks: grants read access to blocks
// - read:bookmarks: grants read access to bookmarks
// - read:custom_emojis: grants read access to custom emojis
// - read:favourites: grants read access to accounts
// - read:filters: grants read access to filters
// - read:follows: grants read access to follows
@ -99,6 +100,7 @@
// read:applications: grants read access to user-managed applications
// read:blocks: grants read access to blocks
// read:bookmarks: grants read access to bookmarks
// read:custom_emojis: grants read access to custom emojis
// read:favourites: grants read access to accounts
// read:filters: grants read access to filters
// read:follows: grants read access to follows

View file

@ -12,4 +12,8 @@ When enabled, the RSS feed for your account will be available at `https://[your-
## Which posts are shared via RSS?
Only your latest 20 Public posts are shared via RSS. Replies and reblogs/boosts are not included. Unlisted posts are not included. In other words, the only posts visible via RSS will be the same ones that are visible when you open your profile in a browser.
Only your latest 20 Public posts are shared via RSS by default. Replies and reblogs/boosts are not included. Unlisted posts are not included. In other words, the only posts visible via RSS will be the same ones that are visible when you open your profile in a browser.
If you want to see more posts, you can provide our standard set of timeline paging parameters ([as per our swagger documentation](https://docs.gotosocial.org/en/latest/api/swagger)) to see beyond the first page.
You can also access Atom and JSON feeds from this same endpoint, but providing the appropriate request content-type header. i.e. `application/atom+xml` for an Atom feed, or `application/feed+json` for a JSON feed.

View file

@ -98,19 +98,32 @@ Some examples:
- Pronouns : she/her
- My other account : @someone@somewhere.com
!!! Tip "ListenBrainz integration"
If you set the key of one of your profile fields to "ListenBrainz" and the value to the URL of your ListenBrainz profile (something like `https://listenbrainz.org/user/your_listenbrainz_username/` -- the slash at the end is important!), then the field will be replaced on the web frontend with whatever you're currently listening to!
This only applies to the web view of your GoToSocial profile, for visitors with Javascript enabled; the "currently listening" value doesn't federate to other servers, only your ListenBrainz URL.
How to set it:
![Field filled with a ListenBrainz URL.](../public/user-settings-listenbrainz-fields.png)
How it looks on the web when you're listening to something:
![The "Now listening to" widget on the web view.](../public/user-settings-listenbrainz.png)
### Visibility and Privacy
#### Visibility Level of Posts to Show on Your Profile
Using this dropdown, you can choose what visibility level(s) of posts should be shown on the public web views of your profile, of your statuses, and in your RSS feed (if you have enabled RSS).
Using this dropdown, you can choose what visibility level(s) of posts should be shown on the public web views of your profile and posts, and in your RSS feed (if enabled).
**By default, GoToSocial shows only Public visibility posts on its web views, not Unlisted.** You can adjust this setting to also show Unlisted visibility posts, which is similar to the default for other ActivityPub softwares like Mastodon etc.
You can also choose to show no posts at all on GoToSocial's web views. This allows you to write posts without having to worry about scrapers, rubberneckers, and other nosy parkers visiting your web profile and looking at your posts.
You can also choose to show no posts at all on the web view of your profile. This allows you to post without having to worry about scrapers, rubberneckers, and other nosy parkers being able to easily look through your posts by opening your profile in a browser.
This setting only applies to the visibility of your own posts. Other user's Unlisted posts are never shown.
Please bear in mind that this setting only applies to the logged-out (unauthenticated) web view of your profile and threads that people visit in their web browser, and RSS feed (if enabled). It does not change the visibility of your posts over the ActivityPub protocol. So even if you choose to show no posts to logged-out visitors to your web profile, folks on instances you federate with will be able to see your posts via ActivityPub if they follow you, have your posts boosted onto their timeline by other people, use a link to search a post of yours, etc.
This setting does not affect visibility of your posts over the ActivityPub protocol, so even if you choose to show no posts on your public web profile, others will be able to see your posts in their client if they follow you, and/or have your posts boosted onto their timeline, use a link to search a post of yours, etc.
Furthermore, while GoToSocial does [transmit a flag to other instances](../federation/actors.md) indicating your preference of what post visibility level to show to logged-out visitors, not all servers will respect this flag; indeed, many servers allow logged-out visitors to look up remote profiles, which can expose your public and unlisted posts. If you require stricter control over who sees your posts, consider posting things at the [followers-only](./posts.md#privatefollowers-only) visibility level, which almost all server softwares respect and properly gate behind authorization.
!!! warning
Be aware that changes to this setting also apply retroactively.

View file

@ -36,6 +36,19 @@ log-db-queries: false
# Default: true
log-client-ip: true
# String. Format to use for formatting log entries.
# Supports "logfmt" and "json", with examples below:
#
# logfmt:
# func=router.(*Router).Start.func1 level=INFO msg="listening on 127.0.0.1:8080"
#
# json:
# {"func":"router.(*Router).Start.func1", "level":"INFO", "msg":"listening on 127.0.0.1:8080"}
#
# Examples: ["logfmt", "json"]
# Default: "logfmt"
log-format: "logfmt"
# String. Format to use for the timestamp in log lines.
# If set to the empty string, the timestamp will be
# ommitted from the logs entirely.
@ -104,14 +117,16 @@ account-domain: ""
# Default: "https"
protocol: "https"
# String. Address to bind the GoToSocial server to.
# This can be an IPv4 address or an IPv6 address (surrounded in square brackets), or a hostname.
# String. Address to bind the GoToSocial HTTP server to.
# This can be an IPv4 address, an IPv6 address, or a hostname.
#
# The default value will bind to all interfaces, which makes the server
# accessible by other machines. For most setups there is no need to change this.
# If you are using GoToSocial in a reverse proxy setup with the proxy running on
# the same machine, you will want to set this to "localhost" or an equivalent,
# so that the proxy can't be bypassed.
# Examples: ["0.0.0.0", "172.128.0.16", "localhost", "[::]", "[2001:db8::fed1]"]
# accessible by other machines. For most setups you won't need to change this.
# However, if you are using GoToSocial in a reverse proxy setup with the proxy
# running on the same machine, you may want to set this to "localhost" or equivalent,
# so that the proxy definitely can't be bypassed.
#
# Examples: ["0.0.0.0", "172.128.0.16", "localhost", "::1", "2001:db8::fed1"]
# Default: "0.0.0.0"
bind-address: "0.0.0.0"
@ -141,8 +156,8 @@ trusted-proxies:
# String. Database type.
# Options: ["postgres","sqlite"]
# Default: "postgres"
db-type: "postgres"
# Default: ""
db-type: "sqlite"
# String. Database address or parameters.
#
@ -157,29 +172,29 @@ db-type: "postgres"
#
# Examples: ["localhost","my.db.host","127.0.0.1","192.111.39.110",":memory:", "sqlite.db"]
# Default: ""
db-address: ""
db-address: "sqlite.db"
# Int. Port for database connection.
# Int. Port for postgres database connection; ignored for sqlite.
# Examples: [5432, 1234, 6969]
# Default: 5432
db-port: 5432
# String. Username for the database connection.
# String. Username for postgres database connection.
# Examples: ["mydbuser","postgres","gotosocial"]
# Default: ""
db-user: ""
# String. Password to use for the database connection
# String. Password to use for postgres database connection.
# Examples: ["password123","verysafepassword","postgres"]
# Default: ""
db-password: ""
# String. Name of the database to use within the provided database type.
# String. Name of the database to use for postgres database connection.
# Examples: ["mydb","postgres","gotosocial"]
# Default: "gotosocial"
db-database: "gotosocial"
# String. Disable, enable, or require SSL/TLS connection to the database.
# String. Disable, enable, or require SSL/TLS connection to postgres.
# If "disable" then no TLS connection will be attempted.
# If "enable" then TLS will be tried, but the database certificate won't be checked (for self-signed certs).
# If "require" then TLS will be required to make a connection, and a valid certificate must be presented.
@ -362,29 +377,61 @@ instance-federation-mode: "blocklist"
# Default: false
instance-federation-spam-filter: false
# Bool. Allow unauthenticated users to make queries to /api/v1/instance/peers?filter=open in order
# to see a list of instances that this instance 'peers' with. Even if set to 'false', then authenticated
# users (members of the instance) will still be able to query the endpoint.
# Bool. Allow unauthenticated users to make queries to /api/v1/instance/peers?filter=open
# in order to see a list of domains that this instance 'peers' with.
#
# Even if set to 'false', then authenticated users (members of the instance)
# will still be able to query these endpoints using an OAuth token.
#
# Options: [true, false]
# Default: false
instance-expose-peers: false
# Bool. Allow unauthenticated users to make queries to /api/v1/instance/peers?filter=suspended in order
# to see a list of instances that this instance blocks/suspends. Even if set to 'false', then authenticated
# users (members of the instance) will still be able to query the endpoint.
# Bool. Allow unauthenticated users to make queries to the following instance API
# endpoints in order to see a list of domains that this instance explicitly blocks,
# including the public reason for each block:
#
# WARNING: Setting this variable to 'true' may result in your instance being scraped by blocklist scrapers.
# - /api/v1/instance/peers?filter=blocklist
# - /api/v1/instance/peers?filter=suspended (deprecated)
# - /api/v1/instance/domain_blocks
#
# Even if set to 'false', then authenticated users (members of the instance)
# will still be able to query these endpoints using an OAuth token.
#
# WARNING: Setting to 'true' may result in your instance being targeted by blocklist scrapers.
# See: https://docs.gotosocial.org/en/latest/admin/domain_blocks/#block-announce-bots
#
# Options: [true, false]
# Default: false
instance-expose-suspended: false
instance-expose-blocklist: false
# Bool. Allow unauthenticated users to view /about/suspended,
# showing the HTML rendered list of instances that this instance blocks/suspends.
# Bool. Allow unauthenticated users to view /about/domain_blocks,
# which shows an HTML-rendered list of domains that this instance blocks,
# including the public reason for each block.
# Options: [true, false]
# Default: false
instance-expose-suspended-web: false
instance-expose-blocklist-web: false
# Bool. Allow unauthenticated users to make queries to the following instance API
# endpoints in order to see a list of domains that this instance explicitly allows
# including the public reason for each allow:
#
# - /api/v1/instance/peers?filter=allowlist
# - /api/v1/instance/domain_allows
#
# Even if set to 'false', then authenticated users (members of the instance)
# will still be able to query these endpoints using an OAuth token.
#
# Options: [true, false]
# Default: false
instance-expose-allowlist: false
# Bool. Allow unauthenticated users to view /about/domain_allows,
# which shows an HTML-rendered list of domains that this instance allows,
# including the public reason for each allow.
# Options: [true, false]
# Default: false
instance-expose-allowlist-web: false
# Bool. Allow unauthenticated users to make queries to /api/v1/timelines/public in order
# to see a list of public posts on this server. Even if set to 'false', then authenticated
@ -393,6 +440,21 @@ instance-expose-suspended-web: false
# Default: false
instance-expose-public-timeline: false
# Bool. Allow unauthenticated access to /api/v1/custom_emojis, which
# exposes the list of custom emojis available to users on this server.
#
# Setting this to 'true' may alleviate issues with clients that do not
# provide an access token in their requests to the emojis endpoint, but
# it also means that anyone can look at what emojis are installed on your
# instance, which may present privacy / safety issues.
#
# Even if set to 'false', authenticated users (ie., instance members)
# will still be able to query the endpoint using an access token.
#
# Options: [true, false]
# Default: false
instance-expose-custom-emojis: false
# Bool. This flag tweaks whether GoToSocial will deliver ActivityPub messages
# to the shared inbox of a recipient, if one is available, instead of delivering
# each message to each actor who should receive a message individually.
@ -460,9 +522,7 @@ instance-stats-mode: ""
# Bool. This flag controls whether local accounts may backdate statuses
# using past dates with the scheduled_at param to /api/v1/statuses.
# This flag does not affect scheduling posts in the future
# (which is currently not implemented anyway),
# nor can it prevent remote accounts from backdating their own statuses.
# This flag can't prevent remote accounts from backdating their own statuses.
#
# If true, all local accounts may backdate statuses.
# If false, status backdating will be disabled and an error will be returned if it's used.
@ -533,6 +593,14 @@ accounts-allow-custom-css: false
# Default: 10000
accounts-custom-css-length: 10000
# Int. The maximum number of profile fields allowed for each account.
#
# Note that going way higher than the default might break federation.
#
# Examples: [4, 6, 12]
# Default: 6
accounts-max-profile-fields: 6
########################
##### MEDIA CONFIG #####
########################
@ -574,6 +642,13 @@ media-video-size-hint: 40MiB
# Default: 40MiB (41943040 bytes)
media-remote-max-size: 40MiB
# Int. Max size in pixels of any one dimension of
# a thumbnail (as input media ratio is preserved).
#
# Examples: [256, 512, 1024]
# Default: 512
media-thumb-max-pixels: 512
# Int. Minimum amount of characters required as an image or video description.
# Examples: [500, 1000, 1500]
# Default: 0 (not required)
@ -795,6 +870,16 @@ statuses-poll-option-max-chars: 50
# Default: 6
statuses-media-max-files: 6
# Int. Maximum number of statuses a user can schedule at time.
# Examples: [300]
# Default: 300
scheduled-statuses-max-total: 300
# Int. Maximum number of statuses a user can schedule for a single day.
# Examples: [25]
# Default: 25
scheduled-statuses-max-daily: 25
##############################
##### LETSENCRYPT CONFIG #####
##############################
@ -993,51 +1078,53 @@ syslog-protocol: "udp"
# Default: "localhost:514"
syslog-address: "localhost:514"
##################################
##### OBSERVABILITY SETTINGS #####
##################################
##############################################
##### OBSERVABILITY AND METRICS SETTINGS #####
##############################################
# String. Header name to use to extract a request or trace ID from. Typically set by a
# loadbalancer or proxy.
# String. Header name to use to extract a request or
# trace ID from. Typically set by a loadbalancer or proxy.
#
# Default: "X-Request-Id"
request-id-header: "X-Request-Id"
# Bool. Enable OpenTelemetry based tracing support.
#
# When enabling tracing, you must also configure a traces
# exporter using the OTEL environment variable documented here:
#
# https://opentelemetry.io/docs/languages/sdk-configuration/general/#otel_traces_exporter
#
# Default: false
tracing-enabled: false
# String. Set the transport protocol for the tracing system. Can either be "grpc"
# for OTLP gRPC, or "http" for OTLP HTTP.
# Options: ["grpc", "http"]
# Default: "grpc"
tracing-transport: "grpc"
# String. Endpoint of the trace ingester. When using the gRPC or HTTP based transports,
# provide the endpoint as a single address/port combination without a protocol scheme.
# Examples: ["localhost:4317"]
# Default: ""
tracing-endpoint: ""
# Bool. Disable TLS for the gRPC and HTTP transport protocols.
# Default: false
tracing-insecure-transport: false
# Bool. Enable OpenTelemetry based metrics support.
#
# To expose Prometheus metrics, you must configure a metrics producer and
# a metrics exporter, using the OTEL environment variables documented here:
#
# https://pkg.go.dev/go.opentelemetry.io/contrib/exporters/autoexport#NewMetricReader
#
# Typically, you will want to set the following environment variables
# (take note of the plural "producers" and singular "exporter"):
#
# - OTEL_METRICS_PRODUCERS=prometheus
# - OTEL_METRICS_EXPORTER=prometheus
#
# With these variables set, a Prometheus metrics endpoint will be exposed at
# localhost:9464/metrics. This can be further configured using the variables:
#
# - OTEL_EXPORTER_OTLP_METRICS_PROTOCOL
# - OTEL_EXPORTER_PROMETHEUS_HOST
# - OTEL_EXPORTER_PROMETHEUS_PORT
#
# For more information, see the GtS metrics documentation here:
#
# https://docs.gotosocial.org/en/latest/advanced/metrics/
#
# Default: false
metrics-enabled: false
# Bool. Enable HTTP Basic Authentication for Prometheus metrics endpoint.
# Default: false
metrics-auth-enabled: false
# String. Username for Prometheus metrics endpoint.
# Default: ""
metrics-auth-username: ""
# String. Password for Prometheus metrics endpoint.
# Default: ""
metrics-auth-password: ""
################################
##### HTTP CLIENT SETTINGS #####
################################
@ -1101,6 +1188,15 @@ http-client:
# Default: false
tls-insecure-skip-verify: false
# Bool. Sets outgoing queries to webfinger, host-meta and nodeinfo to use
# HTTP instead of HTTPS.
#
# THIS SETTING SHOULD BE USED FOR TESTING ONLY! DO NOT CHANGE THIS SETTING
# UNLESS YOU KNOW EXACTLY WHAT YOU'RE DOING AND WHY YOU'RE DOING IT.
#
# Default: false
insecure-outgoing: false
#############################
##### ADVANCED SETTINGS #####
#############################

View file

@ -22,6 +22,11 @@ Restart=on-failure
# Whatever you do, make sure the dir exists and that the gotosocial user has permission to write + read from it.
#Environment="GTS_WAZERO_COMPILATION_CACHE=/gotosocial/.cache"
# If you have set `metrics-enabled` to `true` in your GoToSocial config file, and you want
# to expose Prometheus metrics at localhost:9464/metrics, uncomment the following two lines:
#Environment="OTEL_METRICS_EXPORTER=prometheus"
#Environment="OTEL_METRICS_PRODUCERS=prometheus"
# change if your path to the GoToSocial binary is different
ExecStart=/gotosocial/gotosocial --config-path config.yaml server start
WorkingDirectory=/gotosocial

File diff suppressed because it is too large Load diff

201
go.mod
View file

@ -1,106 +1,105 @@
module code.superseriousbusiness.org/gotosocial
go 1.23.0
toolchain go1.23.3
go 1.24.6
// Replace go-swagger with our version that fixes (ours particularly) use of Go1.23
replace github.com/go-swagger/go-swagger => codeberg.org/superseriousbusiness/go-swagger v0.31.0-gts-go1.23-fix
replace github.com/go-swagger/go-swagger => codeberg.org/superseriousbusiness/go-swagger v0.32.3-gts-go1.23-fix
// Replace modernc/sqlite with our version that fixes the concurrency INTERRUPT issue
replace modernc.org/sqlite => gitlab.com/NyaaaWhatsUpDoc/sqlite v1.37.0-concurrency-workaround
replace modernc.org/sqlite => gitlab.com/NyaaaWhatsUpDoc/sqlite v1.39.0-concurrency-workaround
require (
code.superseriousbusiness.org/activity v1.15.0
code.superseriousbusiness.org/activity v1.17.0
code.superseriousbusiness.org/exif-terminator v0.11.0
code.superseriousbusiness.org/httpsig v1.4.0
code.superseriousbusiness.org/oauth2/v4 v4.8.0
codeberg.org/gruf/go-bytes v1.0.2
codeberg.org/gruf/go-bytesize v1.0.3
code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250812115401-3961e46a7384
codeberg.org/gruf/go-bytesize v1.0.4
codeberg.org/gruf/go-byteutil v1.3.0
codeberg.org/gruf/go-cache/v3 v3.6.1
codeberg.org/gruf/go-caller v0.0.0-20250806133437-db8d0b1f71cf
codeberg.org/gruf/go-debug v1.3.0
codeberg.org/gruf/go-errors/v2 v2.3.2
codeberg.org/gruf/go-fastcopy v1.1.3
codeberg.org/gruf/go-ffmpreg v0.6.7
codeberg.org/gruf/go-fastpath/v2 v2.0.0
codeberg.org/gruf/go-ffmpreg v0.6.12
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
codeberg.org/gruf/go-kv v1.6.5
codeberg.org/gruf/go-kv/v2 v2.0.7
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f
codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760
codeberg.org/gruf/go-mutexes v1.5.2
codeberg.org/gruf/go-mempool v0.0.0-20251003110531-b54adae66253
codeberg.org/gruf/go-mutexes v1.5.8
codeberg.org/gruf/go-runners v1.6.3
codeberg.org/gruf/go-sched v1.2.4
codeberg.org/gruf/go-storage v0.2.0
codeberg.org/gruf/go-structr v0.9.6
codeberg.org/gruf/go-split v1.2.0
codeberg.org/gruf/go-storage v0.3.1
codeberg.org/gruf/go-structr v0.9.12
github.com/DmitriyVTitov/size v1.5.0
github.com/KimMachineGun/automemlimit v0.7.1
github.com/KimMachineGun/automemlimit v0.7.4
github.com/SherClockHolmes/webpush-go v1.4.0
github.com/buckket/go-blurhash v1.1.0
github.com/coreos/go-oidc/v3 v3.14.1
github.com/gin-contrib/cors v1.7.5
github.com/coreos/go-oidc/v3 v3.15.0
github.com/gin-contrib/cors v1.7.6
github.com/gin-contrib/gzip v1.2.3
github.com/gin-contrib/sessions v1.0.3
github.com/gin-gonic/gin v1.10.0
github.com/gin-contrib/sessions v1.0.4
github.com/gin-gonic/gin v1.10.1
github.com/go-playground/form/v4 v4.2.1
github.com/go-swagger/go-swagger v0.31.0
github.com/go-viper/mapstructure/v2 v2.2.1
github.com/go-swagger/go-swagger v0.32.3
github.com/google/go-cmp v0.7.0
github.com/google/uuid v1.6.0
github.com/gorilla/feeds v1.2.0
github.com/gorilla/websocket v1.5.3
github.com/jackc/pgx/v5 v5.7.4
github.com/jackc/pgx/v5 v5.7.6
github.com/k3a/html2text v1.2.1
github.com/microcosm-cc/bluemonday v1.0.27
github.com/miekg/dns v1.1.65
github.com/minio/minio-go/v7 v7.0.91
github.com/miekg/dns v1.1.68
github.com/minio/minio-go/v7 v7.0.95
github.com/mitchellh/mapstructure v1.5.0
github.com/ncruces/go-sqlite3 v0.25.1
github.com/ncruces/go-sqlite3 v0.29.1
github.com/oklog/ulid v1.3.1
github.com/pquerna/otp v1.4.0
github.com/prometheus/client_golang v1.22.0
github.com/pquerna/otp v1.5.0
github.com/rivo/uniseg v0.4.7
github.com/spf13/cobra v1.9.1
github.com/spf13/viper v1.20.1
github.com/stretchr/testify v1.10.0
github.com/tdewolff/minify/v2 v2.23.1
github.com/technologize/otel-go-contrib v1.1.1
github.com/spf13/cast v1.10.0
github.com/spf13/cobra v1.10.1
github.com/spf13/pflag v1.0.10
github.com/spf13/viper v1.21.0
github.com/stretchr/testify v1.11.1
github.com/tdewolff/minify/v2 v2.24.3
github.com/temoto/robotstxt v1.1.2
github.com/tetratelabs/wazero v1.9.0
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e
github.com/ulule/limiter/v3 v3.11.2
github.com/uptrace/bun v1.2.11
github.com/uptrace/bun/dialect/pgdialect v1.2.11
github.com/uptrace/bun/dialect/sqlitedialect v1.2.11
github.com/uptrace/bun/extra/bunotel v1.2.11
github.com/uptrace/bun v1.2.15
github.com/uptrace/bun/dialect/pgdialect v1.2.15
github.com/uptrace/bun/dialect/sqlitedialect v1.2.15
github.com/uptrace/bun/extra/bunotel v1.2.15
github.com/wagslane/go-password-validator v0.3.0
github.com/yuin/goldmark v1.7.11
go.opentelemetry.io/otel v1.35.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0
go.opentelemetry.io/otel/exporters/prometheus v0.57.0
go.opentelemetry.io/otel/metric v1.35.0
go.opentelemetry.io/otel/sdk v1.35.0
go.opentelemetry.io/otel/sdk/metric v1.35.0
go.opentelemetry.io/otel/trace v1.35.0
github.com/yuin/goldmark v1.7.13
go.opentelemetry.io/contrib/exporters/autoexport v0.63.0
go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0
go.opentelemetry.io/otel v1.38.0
go.opentelemetry.io/otel/metric v1.38.0
go.opentelemetry.io/otel/sdk v1.38.0
go.opentelemetry.io/otel/sdk/metric v1.38.0
go.opentelemetry.io/otel/trace v1.38.0
go.uber.org/automaxprocs v1.6.0
golang.org/x/crypto v0.37.0
golang.org/x/image v0.26.0
golang.org/x/net v0.39.0
golang.org/x/oauth2 v0.29.0
golang.org/x/sys v0.32.0
golang.org/x/text v0.24.0
golang.org/x/crypto v0.42.0
golang.org/x/image v0.31.0
golang.org/x/net v0.44.0
golang.org/x/oauth2 v0.31.0
golang.org/x/sys v0.36.0
golang.org/x/text v0.29.0
gopkg.in/mcuadros/go-syslog.v2 v2.3.0
gopkg.in/yaml.v3 v3.0.1
modernc.org/sqlite v1.37.0
modernc.org/sqlite v1.39.0
mvdan.cc/xurls/v2 v2.6.0
)
require (
code.superseriousbusiness.org/go-jpeg-image-structure/v2 v2.3.0 // indirect
code.superseriousbusiness.org/go-png-image-structure/v2 v2.3.0 // indirect
codeberg.org/gruf/go-fastpath/v2 v2.0.0 // indirect
codeberg.org/gruf/go-mangler v1.4.4 // indirect
codeberg.org/gruf/go-kv v1.6.5 // indirect
codeberg.org/gruf/go-mangler/v2 v2.0.6 // indirect
codeberg.org/gruf/go-maps v1.0.4 // indirect
codeberg.org/gruf/go-xunsafe v0.0.0-20250809104800-512a9df57d73 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
@ -108,9 +107,9 @@ require (
github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/bytedance/sonic v1.13.2 // indirect
github.com/bytedance/sonic v1.13.3 // indirect
github.com/bytedance/sonic/loader v0.2.4 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
@ -121,13 +120,13 @@ require (
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/gin-contrib/sse v1.0.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect
github.com/go-errors/errors v1.1.1 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-jose/go-jose/v4 v4.1.1 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.23.0 // indirect
github.com/go-openapi/errors v0.22.0 // indirect
@ -143,17 +142,18 @@ require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.26.0 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d // indirect
github.com/gorilla/context v1.1.2 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/gorilla/handlers v1.5.2 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
github.com/gorilla/sessions v1.4.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
@ -165,13 +165,13 @@ require (
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/klauspost/cpuid/v2 v2.2.11 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/minio/crc64nvme v1.0.1 // indirect
github.com/minio/crc64nvme v1.0.2 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
@ -181,48 +181,63 @@ require (
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/ncruces/julianday v1.0.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/philhofer/fwd v1.2.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/prometheus/client_golang v1.23.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.65.0 // indirect
github.com/prometheus/otlptranslator v0.0.2 // indirect
github.com/prometheus/procfs v0.17.0 // indirect
github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.12.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tdewolff/parse/v2 v2.7.23 // indirect
github.com/tdewolff/parse/v2 v2.8.3 // indirect
github.com/tinylib/msgp v1.3.0 // indirect
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
github.com/toqueteos/webbrowser v1.2.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/ugorji/go/codec v1.3.0 // indirect
github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
go.mongodb.org/mongo-driver v1.17.3 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.16.0 // indirect
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/sync v0.13.0 // indirect
golang.org/x/tools v0.31.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
google.golang.org/grpc v1.71.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
go.opentelemetry.io/contrib/bridges/prometheus v0.63.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect
go.opentelemetry.io/otel/log v0.14.0 // indirect
go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/arch v0.18.0 // indirect
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
golang.org/x/mod v0.27.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/tools v0.36.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
google.golang.org/grpc v1.75.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
modernc.org/libc v1.62.1 // indirect
modernc.org/libc v1.66.3 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.9.1 // indirect
modernc.org/memory v1.11.0 // indirect
)

451
go.sum generated
View file

@ -1,5 +1,5 @@
code.superseriousbusiness.org/activity v1.15.0 h1:XwdO/1ssry8GCLWDFlUxSb+lNpUvdjkKG3HVHTEkvi4=
code.superseriousbusiness.org/activity v1.15.0/go.mod h1:BTMWJIAuwDH1w+ieRP5N+T5LipbXjw35U6KZy0V/xdg=
code.superseriousbusiness.org/activity v1.17.0 h1:01x4LyvL5fzKgtce+o3mqYbR1O+RaL6j/z7v/B6ivqo=
code.superseriousbusiness.org/activity v1.17.0/go.mod h1:BTMWJIAuwDH1w+ieRP5N+T5LipbXjw35U6KZy0V/xdg=
code.superseriousbusiness.org/exif-terminator v0.11.0 h1:Hof0MCcsa+1fS17gf86fTTZ8AQnMY9h9kzcc+2C6mVg=
code.superseriousbusiness.org/exif-terminator v0.11.0/go.mod h1:9sutT1axa/kSdlPLlRFjCNKmyo/KNx8eX3XZvWBlAEY=
code.superseriousbusiness.org/go-jpeg-image-structure/v2 v2.3.0 h1:r9uq8StaSHYKJ8DklR9Xy+E9c40G1Z8yj5TRGi8L6+4=
@ -8,16 +8,16 @@ code.superseriousbusiness.org/go-png-image-structure/v2 v2.3.0 h1:I512jiIeXDC4//
code.superseriousbusiness.org/go-png-image-structure/v2 v2.3.0/go.mod h1:SNHomXNW88o1pFfLHpD4KsCZLfcr4z5dm+xcX5SV10A=
code.superseriousbusiness.org/httpsig v1.4.0 h1:g9+KQMoTG0oR0II5gYb5pVVdNjbc7CiiuqK8vcZjeQg=
code.superseriousbusiness.org/httpsig v1.4.0/go.mod h1:i2AKpj/WbA/o/UTvia9TAREzt0jP1AH3T1Uxjyhdzlw=
code.superseriousbusiness.org/oauth2/v4 v4.8.0 h1:4LVXoPJXKgmDfwDegzBQPNpsdleMaL6YmDgFi6UDgEE=
code.superseriousbusiness.org/oauth2/v4 v4.8.0/go.mod h1:+RLRBXPkjP/VhIC/46dcZkx3t5IvBSJYOjVCPgeWors=
codeberg.org/gruf/go-bytes v1.0.2 h1:malqE42Ni+h1nnYWBUAJaDDtEzF4aeN4uPN8DfMNNvo=
codeberg.org/gruf/go-bytes v1.0.2/go.mod h1:1v/ibfaosfXSZtRdW2rWaVrDXMc9E3bsi/M9Ekx39cg=
codeberg.org/gruf/go-bytesize v1.0.3 h1:Tz8tCxhPLeyM5VryuBNjUHgKmLj4Bx9RbPaUSA3qg6g=
codeberg.org/gruf/go-bytesize v1.0.3/go.mod h1:n/GU8HzL9f3UNp/mUKyr1qVmTlj7+xacpp0OHfkvLPs=
code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250812115401-3961e46a7384 h1:eJzULGUyhHGk2DdQxX/jbH9FKZOyoIF90p3dzukCfLA=
code.superseriousbusiness.org/oauth2/v4 v4.5.4-0.20250812115401-3961e46a7384/go.mod h1:4x61i4C725jkXOpnUPFNfmiEthF6FZc/byADbalp+F8=
codeberg.org/gruf/go-bytesize v1.0.4 h1:LEojK46lUoE748Om7yldx6kLe6jCCuiytz5IZ8vH35g=
codeberg.org/gruf/go-bytesize v1.0.4/go.mod h1:n/GU8HzL9f3UNp/mUKyr1qVmTlj7+xacpp0OHfkvLPs=
codeberg.org/gruf/go-byteutil v1.3.0 h1:nRqJnCcRQ7xbfU6azw7zOzJrSMDIJHBqX6FL9vEMYmU=
codeberg.org/gruf/go-byteutil v1.3.0/go.mod h1:chgnZz1LUcfaObaIFglxF5MRYQkJGjQf4WwVz95ccCM=
codeberg.org/gruf/go-cache/v3 v3.6.1 h1:sY1XhYeskjZAuYeMm5R0o4Qymru5taNbzmZPSn1oXLE=
codeberg.org/gruf/go-cache/v3 v3.6.1/go.mod h1:JUNjc4E8gRccn3t+B99akxURFrU6NTDkvFVcwiZirnw=
codeberg.org/gruf/go-caller v0.0.0-20250806133437-db8d0b1f71cf h1:Rzu7WLpscj2w1N+ClIHlJoTYf9SuqZrZ7E4f9T7jGdw=
codeberg.org/gruf/go-caller v0.0.0-20250806133437-db8d0b1f71cf/go.mod h1:jEyYiqCzH1TaxfclSFYthE32oI0dsMnRS6EHqy6y0uo=
codeberg.org/gruf/go-debug v1.3.0 h1:PIRxQiWUFKtGOGZFdZ3Y0pqyfI0Xr87j224IYe2snZs=
codeberg.org/gruf/go-debug v1.3.0/go.mod h1:N+vSy9uJBQgpQcJUqjctvqFz7tBHJf+S/PIjLILzpLg=
codeberg.org/gruf/go-errors/v2 v2.3.2 h1:8ItWaOMfhDaqrJK1Pw8MO0Nu+o/tVcQtR5cJ58Vc4zo=
@ -26,38 +26,44 @@ codeberg.org/gruf/go-fastcopy v1.1.3 h1:Jo9VTQjI6KYimlw25PPc7YLA3Xm+XMQhaHwKnM7x
codeberg.org/gruf/go-fastcopy v1.1.3/go.mod h1:GDDYR0Cnb3U/AIfGM3983V/L+GN+vuwVMvrmVABo21s=
codeberg.org/gruf/go-fastpath/v2 v2.0.0 h1:iAS9GZahFhyWEH0KLhFEJR+txx1ZhMXxYzu2q5Qo9c0=
codeberg.org/gruf/go-fastpath/v2 v2.0.0/go.mod h1:3pPqu5nZjpbRrOqvLyAK7puS1OfEtQvjd6342Cwz56Q=
codeberg.org/gruf/go-ffmpreg v0.6.7 h1:WBAgmHT58oqHBm6ckU1jPz7qamqFJj/Uag0yalevpPo=
codeberg.org/gruf/go-ffmpreg v0.6.7/go.mod h1:tGqIMh/I2cizqauxxNAN+WGkICI0j5G3xwF1uBkyw1E=
codeberg.org/gruf/go-ffmpreg v0.6.12 h1:mPdRx1TAQJQPhRkTOOHnRSY6omNCLJ7M6ajjuEMNNvE=
codeberg.org/gruf/go-ffmpreg v0.6.12/go.mod h1:tGqIMh/I2cizqauxxNAN+WGkICI0j5G3xwF1uBkyw1E=
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf h1:84s/ii8N6lYlskZjHH+DG6jyia8w2mXMZlRwFn8Gs3A=
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf/go.mod h1:zZAICsp5rY7+hxnws2V0ePrWxE0Z2Z/KXcN3p/RQCfk=
codeberg.org/gruf/go-kv v1.6.5 h1:ttPf0NA8F79pDqBttSudPTVCZmGncumeNIxmeM9ztz0=
codeberg.org/gruf/go-kv v1.6.5/go.mod h1:c4PsGqw05bDScvISpK+d31SiDEpBorweCL50hsiK3dc=
codeberg.org/gruf/go-kv/v2 v2.0.7 h1:RdTY28NX1N/lc3/ivuasnyqnMdQKwV0es3iqSM/DG44=
codeberg.org/gruf/go-kv/v2 v2.0.7/go.mod h1:uo6rPR14/ll+SDSU3K7DfINNmWD5NJ0EiahPayOguy0=
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f h1:Ss6Z+vygy+jOGhj96d/GwsYYDd22QmIcH74zM7/nQkw=
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f/go.mod h1:F9pl4h34iuVN7kucKam9fLwsItTc+9mmaKt7pNXRd/4=
codeberg.org/gruf/go-loosy v0.0.0-20231007123304-bb910d1ab5c4 h1:IXwfoU7f2whT6+JKIKskNl/hBlmWmnF1vZd84Eb3cyA=
codeberg.org/gruf/go-loosy v0.0.0-20231007123304-bb910d1ab5c4/go.mod h1:fiO8HE1wjZCephcYmRRsVnNI/i0+mhy44Z5dQalS0rM=
codeberg.org/gruf/go-mangler v1.4.4 h1:moQl7FSSLLaByS7w5UP7b3Z7r2ex/F4IpvSp+PyRWK4=
codeberg.org/gruf/go-mangler v1.4.4/go.mod h1:mDmW8Ia352RvNFaXoP9K60TgcmCZJtX0j6wm3vjAsJE=
codeberg.org/gruf/go-mangler/v2 v2.0.6 h1:c3cwnI6Mi17EAwGSYGNMN6+9PMzaIj2GLAKx9DKZwoI=
codeberg.org/gruf/go-mangler/v2 v2.0.6/go.mod h1:CXIm7zAWPdNmZVAGM1NRiF/ekJTPE7YTb8kiRxiEFaQ=
codeberg.org/gruf/go-maps v1.0.4 h1:K+Ww4vvR3TZqm5jqrKVirmguZwa3v1VUvmig2SE8uxY=
codeberg.org/gruf/go-maps v1.0.4/go.mod h1:ASX7osM7kFwt5O8GfGflcFjrwYGD8eIuRLl/oMjhEi8=
codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760 h1:m2/UCRXhjDwAg4vyji6iKCpomKw6P4PmBOUi5DvAMH4=
codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760/go.mod h1:E3RcaCFNq4zXpvaJb8lfpPqdUAmSkP5F1VmMiEUYTEk=
codeberg.org/gruf/go-mutexes v1.5.2 h1:rp2o774ApGUVtOHDksqtBiqIcvniVfgFWSazszDluy0=
codeberg.org/gruf/go-mutexes v1.5.2/go.mod h1:AnhagsMzUISL/nBVwhnHwDwTZOAxMILwCOG8/wKOblg=
codeberg.org/gruf/go-mempool v0.0.0-20251003110531-b54adae66253 h1:qPAY72xCWlySVROSNZecfLGAyeV/SiXmPmfhUU+o3Xw=
codeberg.org/gruf/go-mempool v0.0.0-20251003110531-b54adae66253/go.mod h1:761koiXmqfgzvu5mez2Rk7YlwWilpqJ/zv5hIA6NoNI=
codeberg.org/gruf/go-mutexes v1.5.8 h1:HRGnvT4COb3jX9xdeoSUUbjPgmk5kXPuDfld9ksUJKA=
codeberg.org/gruf/go-mutexes v1.5.8/go.mod h1:21sy/hWH8dDQBk7ocsxqo2GNpWiIir+e82RG3hjnN20=
codeberg.org/gruf/go-runners v1.6.3 h1:To/AX7eTrWuXrTkA3RA01YTP5zha1VZ68LQ+0D4RY7E=
codeberg.org/gruf/go-runners v1.6.3/go.mod h1:oXAaUmG2VxoKttpCqZGv5nQBeSvZSR2BzIk7h1yTRlU=
codeberg.org/gruf/go-sched v1.2.4 h1:ddBB9o0D/2oU8NbQ0ldN5aWxogpXPRBATWi58+p++Hw=
codeberg.org/gruf/go-sched v1.2.4/go.mod h1:wad6l+OcYGWMA2TzNLMmLObsrbBDxdJfEy5WvTgBjNk=
codeberg.org/gruf/go-storage v0.2.0 h1:mKj3Lx6AavEkuXXtxqPhdq+akW9YwrnP16yQBF7K5ZI=
codeberg.org/gruf/go-storage v0.2.0/go.mod h1:o3GzMDE5QNUaRnm/daUzFqvuAaC4utlgXDXYO79sWKU=
codeberg.org/gruf/go-structr v0.9.6 h1:FSbJ1A0ubTQB82rC0K4o6qyiqrDGH1t9ivttm8Zy64o=
codeberg.org/gruf/go-structr v0.9.6/go.mod h1:9k5hYztZ4PsBS+m1v5hUTeFiVUBTLF5VA7d9cd1OEMs=
codeberg.org/superseriousbusiness/go-swagger v0.31.0-gts-go1.23-fix h1:+JvBZqsQfdT+ROnk2DkvXsKQ9QBorKKKBk5fBqw62I8=
codeberg.org/superseriousbusiness/go-swagger v0.31.0-gts-go1.23-fix/go.mod h1:WSigRRWEig8zV6t6Sm8Y+EmUjlzA/HoaZJ5edupq7po=
codeberg.org/gruf/go-split v1.2.0 h1:PmzL23nVEVHm8VxjsJmv4m4wGQz2bGgQw52dgSSj65c=
codeberg.org/gruf/go-split v1.2.0/go.mod h1:0rejWJpqvOoFAd7nwm5tIXYKaAqjtFGOXmTqQV+VO38=
codeberg.org/gruf/go-storage v0.3.1 h1:g66UIM/xXnEk9ejT+W0T9s/PODBZhXa/8ajzeY/MELI=
codeberg.org/gruf/go-storage v0.3.1/go.mod h1:r43n/zi7YGOCl2iSl7AMI27D1zcWS65Bi2+5xDzypeo=
codeberg.org/gruf/go-structr v0.9.12 h1:yMopvexnuKgZme9WgvIhrJaAuAjfper/x38xsVuJOOo=
codeberg.org/gruf/go-structr v0.9.12/go.mod h1:sP2ZSjM5X5XKlxuhAbTKuVQm9DWbHsrQRuTl3MUwbHw=
codeberg.org/gruf/go-xunsafe v0.0.0-20250809104800-512a9df57d73 h1:pRaOwIOS1WSZoPCAvE0H1zpv+D4gF37OVppybffqdI8=
codeberg.org/gruf/go-xunsafe v0.0.0-20250809104800-512a9df57d73/go.mod h1:9wkq+dmHjUhB/0ZxDUWAwsWuXwwGyx5N1dDCB9hpWs8=
codeberg.org/superseriousbusiness/go-swagger v0.32.3-gts-go1.23-fix h1:k76/Th+bruqU/d+dB0Ru466ctTF2aVjKpisy/471ILE=
codeberg.org/superseriousbusiness/go-swagger v0.32.3-gts-go1.23-fix/go.mod h1:lAwO1nKff3qNRJYVQeTCl1am5pcNiiA2VyDf8TqzS24=
github.com/DmitriyVTitov/size v1.5.0 h1:/PzqxYrOyOUX1BXj6J9OuVRVGe+66VL4D9FlUaW515g=
github.com/DmitriyVTitov/size v1.5.0/go.mod h1:le6rNI4CoLQV1b9gzp1+3d7hMAD/uu2QcJ+aYbNgiU0=
github.com/KimMachineGun/automemlimit v0.7.1 h1:QcG/0iCOLChjfUweIMC3YL5Xy9C3VBeNmCZHrZfJMBw=
github.com/KimMachineGun/automemlimit v0.7.1/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=
github.com/KimMachineGun/automemlimit v0.7.4 h1:UY7QYOIfrr3wjjOAqahFmC3IaQCLWvur9nmfIn6LnWk=
github.com/KimMachineGun/automemlimit v0.7.4/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
@ -67,10 +73,12 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/SherClockHolmes/webpush-go v1.4.0 h1:ocnzNKWN23T9nvHi6IfyrQjkIc0oJWv1B1pULsf9i3s=
github.com/SherClockHolmes/webpush-go v1.4.0/go.mod h1:XSq8pKX11vNV8MJEMwjrlTkxhAj1zKfxmyhdV7Pd6UA=
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4=
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
@ -81,13 +89,13 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/buckket/go-blurhash v1.1.0 h1:X5M6r0LIvwdvKiUtiNcRL2YlmOfMzYobI3VCKCZc9Do=
github.com/buckket/go-blurhash v1.1.0/go.mod h1:aT2iqo5W9vu9GpyoLErKfTHwgODsZp3bQfXjXJUxNb8=
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
github.com/bytedance/sonic v1.13.3 h1:MS8gmaH16Gtirygw7jV91pDCN33NyMrPbN7qiYhEsF0=
github.com/bytedance/sonic v1.13.3/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
@ -95,8 +103,8 @@ github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJ
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ=
github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4=
github.com/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk=
github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
github.com/coreos/go-oidc/v3 v3.15.0 h1:R6Oz8Z4bqWR7VFQ+sPSvZPQv4x8M+sJkDO5ojgwlyAg=
github.com/coreos/go-oidc/v3 v3.15.0/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -121,41 +129,43 @@ github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e h1:IxIbA7VbC
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fxamacker/cbor v1.5.1 h1:XjQWBgdmQyqimslUh5r4tUGmoqzHmBFQOImkWGi2awg=
github.com/fxamacker/cbor v1.5.1/go.mod h1:3aPGItF174ni7dDzd6JZ206H8cmr4GDNBGpPa971zsU=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/gin-contrib/cors v1.7.5 h1:cXC9SmofOrRg0w9PigwGlHG3ztswH6bqq4vJVXnvYMk=
github.com/gin-contrib/cors v1.7.5/go.mod h1:4q3yi7xBEDDWKapjT2o1V7mScKDDr8k+jZ0fSquGoy0=
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
github.com/gavv/httpexpect/v2 v2.17.0 h1:nIJqt5v5e4P7/0jODpX2gtSw+pHXUqdP28YcjqwDZmE=
github.com/gavv/httpexpect/v2 v2.17.0/go.mod h1:E8ENFlT9MZ3Si2sfM6c6ONdwXV2noBCGkhA+lkJgkP0=
github.com/gin-contrib/cors v1.7.6 h1:3gQ8GMzs1Ylpf70y8bMw4fVpycXIeX1ZemuSQIsnQQY=
github.com/gin-contrib/cors v1.7.6/go.mod h1:Ulcl+xN4jel9t1Ry8vqph23a60FwH9xVLd+3ykmTjOk=
github.com/gin-contrib/gzip v1.2.3 h1:dAhT722RuEG330ce2agAs75z7yB+NKvX/ZM1r8w0u2U=
github.com/gin-contrib/gzip v1.2.3/go.mod h1:ad72i4Bzmaypk8M762gNXa2wkxxjbz0icRNnuLJ9a/c=
github.com/gin-contrib/sessions v1.0.3 h1:AZ4j0AalLsGqdrKNbbrKcXx9OJZqViirvNGsJTxcQps=
github.com/gin-contrib/sessions v1.0.3/go.mod h1:5i4XMx4KPtQihnzxEqG9u1K446lO3G19jAi2GtbfsAI=
github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/gin-contrib/sessions v1.0.4 h1:ha6CNdpYiTOK/hTp05miJLbpTSNfOnFg5Jm2kbcqy8U=
github.com/gin-contrib/sessions v1.0.4/go.mod h1:ccmkrb2z6iU2osiAHZG3x3J4suJK+OU27oqzlWOqQgs=
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-errors/errors v1.1.1 h1:ljK/pL5ltg3qoN+OtN6yCv9HWSfMwxSx90GJCZQxYNg=
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI=
github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
@ -193,17 +203,17 @@ github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b h1:khEcpUM4yFcxg4/FHQWkvVRmgijNXRfzkIDHh23ggEo=
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d h1:C/hKUcHT483btRbeGkrRjJz+Zbcj8audldIi9tRJDCc=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
@ -243,8 +253,10 @@ github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzq
github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248=
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
@ -259,8 +271,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg=
github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
@ -280,8 +292,8 @@ github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zt
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU=
github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@ -293,21 +305,25 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
github.com/miekg/dns v1.1.65 h1:0+tIPHzUW0GCge7IiK3guGP57VAw7hoPDfApjkMD1Fc=
github.com/miekg/dns v1.1.65/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck=
github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY=
github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
github.com/minio/crc64nvme v1.0.2 h1:6uO1UxGAD+kwqWWp7mBFsi5gAse66C4NXO8cmcVculg=
github.com/minio/crc64nvme v1.0.2/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.91 h1:tWLZnEfo3OZl5PoXQwcwTAPNNrjyWwOh6cbZitW5JQc=
github.com/minio/minio-go/v7 v7.0.91/go.mod h1:uvMUcGrpgeSAAI6+sD3818508nUyMULw94j2Nxku/Go=
github.com/minio/minio-go/v7 v7.0.95 h1:ywOUPg+PebTMTzn9VDsoFJy32ZuARN9zhB+K3IYEvYU=
github.com/minio/minio-go/v7 v7.0.95/go.mod h1:wOOX3uxS334vImCNRVyIDdXX9OsXDm89ToynKgqUKlo=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@ -320,12 +336,10 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs=
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/ncruces/go-sqlite3 v0.25.1 h1:nRK2mZ0jLNFJco8QFZ9+dCXxOGe6Re8bbG5o8gyalr8=
github.com/ncruces/go-sqlite3 v0.25.1/go.mod h1:4BtkHRLbX5hE0PhBxJ11qETTwL7M4lk0ttru9nora1E=
github.com/ncruces/go-sqlite3 v0.29.1 h1:NIi8AISWBToRHyoz01FXiTNvU147Tqdibgj2tFzJCqM=
github.com/ncruces/go-sqlite3 v0.29.1/go.mod h1:PpccBNNhvjwUOwDQEn2gXQPFPTWdlromj0+fSkd5KSg=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
@ -334,26 +348,30 @@ github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
github.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ=
github.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI=
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b h1:aUNXCGgukb4gtY99imuIeoh8Vr0GSwAlYxPAhqZrpFc=
@ -368,36 +386,38 @@ github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a/go.mod h1:
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/smarty/assertions v1.16.0 h1:EvHNkdRA4QHMrn75NZSoUQ/mAUXAYWfatfB01yTCzfY=
github.com/smarty/assertions v1.16.0/go.mod h1:duaaFdCS0K9dnoM50iyek/eYINOZ64gbh1Xlf6LG7AI=
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
@ -405,65 +425,64 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/tdewolff/minify/v2 v2.23.1 h1:r6sKQrumHzskWZRdhiRa+pZhn7CdBMojACNP9fuKpXQ=
github.com/tdewolff/minify/v2 v2.23.1/go.mod h1:RkUGjklq6uIsBoOdzY3ll35HKKQ2aFqLQhnanBHhDyU=
github.com/tdewolff/parse/v2 v2.7.23 h1:sCW2PNTCM1yVldh5YK/8wrpRI9rSbloUZWjAydlN2IA=
github.com/tdewolff/parse/v2 v2.7.23/go.mod h1:I7TXO37t3aSG9SlPUBefAhgIF8nt7yYUwVGgETIoBcA=
github.com/tdewolff/minify/v2 v2.24.3 h1:BaKgWSFLKbKDiUskbeRgbe2n5d1Ci1x3cN/eXna8zOA=
github.com/tdewolff/minify/v2 v2.24.3/go.mod h1:1JrCtoZXaDbqioQZfk3Jdmr0GPJKiU7c1Apmb+7tCeE=
github.com/tdewolff/parse/v2 v2.8.3 h1:5VbvtJ83cfb289A1HzRA9sf02iT8YyUwN84ezjkdY1I=
github.com/tdewolff/parse/v2 v2.8.3/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLBLd6dlIXYqo=
github.com/tdewolff/test v1.0.11 h1:FdLbwQVHxqG16SlkGveC0JVyrJN62COWTRyUFzfbtBE=
github.com/tdewolff/test v1.0.11/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
github.com/technologize/otel-go-contrib v1.1.1 h1:wZH9aSPNWZWIkEh3vfaKfMb15AJ80jJ1aVj/4GZdqIw=
github.com/technologize/otel-go-contrib v1.1.1/go.mod h1:dCN/wj2WyUO8aFZFdIN+6tfJHImjTML/8r2YVYAy3So=
github.com/temoto/robotstxt v1.1.2 h1:W2pOjSJ6SWvldyEuiFXNxz3xZ8aiWX5LbfDiOFd7Fxg=
github.com/temoto/robotstxt v1.1.2/go.mod h1:+1AmkuG3IYkh1kv0d2qEB9Le88ehNO0zwOr3ujewlOo=
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
github.com/tidwall/btree v1.4.2 h1:PpkaieETJMUxYNADsjgtNRcERX7mGc/GP2zp/r5FM3g=
github.com/tidwall/btree v1.4.2/go.mod h1:LGm8L/DZjPLmeWGjv5kFrY8dL4uVhMmzmmLYmsObdKE=
github.com/tidwall/buntdb v1.3.2 h1:qd+IpdEGs0pZci37G4jF51+fSKlkuUTMXuHhXL1AkKg=
github.com/tidwall/buntdb v1.3.2/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg=
github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8=
github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ=
github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE=
github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw=
github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e h1:tD38/4xg4nuQCASJ/JxcvCHNb46w0cdAaJfkzQOO1bA=
github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e/go.mod h1:krvJ5AY/MjdPkTeRgMYbIDhbbbVvnPQPzsIsDJO8xrY=
github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ=
github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA=
github.com/ulule/limiter/v3 v3.11.2/go.mod h1:QG5GnFOCV+k7lrL5Y8kgEeeflPH3+Cviqlqa8SVSQxI=
github.com/uptrace/bun v1.2.11 h1:l9dTymsdZZAoSZ1+Qo3utms0RffgkDbIv+1UGk8N1wQ=
github.com/uptrace/bun v1.2.11/go.mod h1:ww5G8h59UrOnCHmZ8O1I/4Djc7M/Z3E+EWFS2KLB6dQ=
github.com/uptrace/bun/dialect/pgdialect v1.2.11 h1:n0VKWm1fL1dwJK5TRxYYLaRKRe14BOg2+AQgpvqzG/M=
github.com/uptrace/bun/dialect/pgdialect v1.2.11/go.mod h1:NvV1S/zwtwBnW8yhJ3XEKAQEw76SkeH7yUhfrx3W1Eo=
github.com/uptrace/bun/dialect/sqlitedialect v1.2.11 h1:t4OIcbkWnRPshRj7ZnbHVwUENa3OHhCUruyFcl3P+TY=
github.com/uptrace/bun/dialect/sqlitedialect v1.2.11/go.mod h1:XHFFTvdlNtNFWPhpRAConN6DnVgt9EHr5G5IIarHYyg=
github.com/uptrace/bun/extra/bunotel v1.2.11 h1:ddt96XrbvlVZu5vBddP6WmbD6bdeJTaWY9jXlfuJKZE=
github.com/uptrace/bun/extra/bunotel v1.2.11/go.mod h1:w6Mhie5tLFeP+5ryjq4PvgZEESRJ1iL2cbvxhm+f8q4=
github.com/uptrace/bun v1.2.15 h1:Ut68XRBLDgp9qG9QBMa9ELWaZOmzHNdczHQdrOZbEFE=
github.com/uptrace/bun v1.2.15/go.mod h1:Eghz7NonZMiTX/Z6oKYytJ0oaMEJ/eq3kEV4vSqG038=
github.com/uptrace/bun/dialect/pgdialect v1.2.15 h1:er+/3giAIqpfrXJw+KP9B7ujyQIi5XkPnFmgjAVL6bA=
github.com/uptrace/bun/dialect/pgdialect v1.2.15/go.mod h1:QSiz6Qpy9wlGFsfpf7UMSL6mXAL1jDJhFwuOVacCnOQ=
github.com/uptrace/bun/dialect/sqlitedialect v1.2.15 h1:7upGMVjFRB1oI78GQw6ruNLblYn5CR+kxqcbbeBBils=
github.com/uptrace/bun/dialect/sqlitedialect v1.2.15/go.mod h1:c7YIDaPNS2CU2uI1p7umFuFWkuKbDcPDDvp+DLHZnkI=
github.com/uptrace/bun/extra/bunotel v1.2.15 h1:6KAvKRpH9BC/7n3eMXVgDYLqghHf2H3FJOvxs/yjFJM=
github.com/uptrace/bun/extra/bunotel v1.2.15/go.mod h1:qnASdcJVuoEE+13N3Gd8XHi5gwCydt2S1TccJnefH2k=
github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 h1:ZjUj9BLYf9PEqBn8W/OapxhPjVRdC6CsXTdULHsyk5c=
github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2/go.mod h1:O8bHQfyinKwTXKkiKNGmLQS7vRsqRxIQTFZpYpHK3IQ=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.59.0 h1:Qu0qYHfXvPk1mSLNqcFtEk6DpxgA26hy6bmydotDpRI=
github.com/valyala/fasthttp v1.59.0/go.mod h1:GTxNb9Bc6r2a9D0TWNSPwDz78UxnTGBViY3xZNEqyYU=
github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c=
github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
@ -485,42 +504,68 @@ github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FB
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.7.11 h1:ZCxLyDMtz0nT2HFfsYG8WZ47Trip2+JyLysKcMYE5bo=
github.com/yuin/goldmark v1.7.11/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
gitlab.com/NyaaaWhatsUpDoc/sqlite v1.37.0-concurrency-workaround h1:QbfrBqNKgAFSSK89fYf547vxDQuz8p6iJUzzAMrusNk=
gitlab.com/NyaaaWhatsUpDoc/sqlite v1.37.0-concurrency-workaround/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM=
github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA=
github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
gitlab.com/NyaaaWhatsUpDoc/sqlite v1.39.0-concurrency-workaround h1:+e2m4Ycgsri3YaePPAuYcTawQxklz0q/3CbKEbqxhOM=
gitlab.com/NyaaaWhatsUpDoc/sqlite v1.39.0-concurrency-workaround/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E=
go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ=
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
go.opentelemetry.io/otel/exporters/prometheus v0.57.0 h1:AHh/lAP1BHrY5gBwk8ncc25FXWm/gmmY3BX258z5nuk=
go.opentelemetry.io/otel/exporters/prometheus v0.57.0/go.mod h1:QpFWz1QxqevfjwzYdbMb4Y1NnlJvqSGwyuU0B4iuc9c=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.opentelemetry.io/contrib/bridges/prometheus v0.63.0 h1:/Rij/t18Y7rUayNg7Id6rPrEnHgorxYabm2E6wUdPP4=
go.opentelemetry.io/contrib/bridges/prometheus v0.63.0/go.mod h1:AdyDPn6pkbkt2w01n3BubRVk7xAsCRq1Yg1mpfyA/0E=
go.opentelemetry.io/contrib/exporters/autoexport v0.63.0 h1:NLnZybb9KkfMXPwZhd5diBYJoVxiO9Qa06dacEA7ySY=
go.opentelemetry.io/contrib/exporters/autoexport v0.63.0/go.mod h1:OvRg7gm5WRSCtxzGSsrFHbDLToYlStHNZQ+iPNIyD6g=
go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 h1:PeBoRj6af6xMI7qCupwFvTbbnd49V7n5YpG6pg8iDYQ=
go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0/go.mod h1:ingqBCtMCe8I4vpz/UVzCW6sxoqgZB37nao91mLQ3Bw=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo=
go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE=
go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM=
go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg=
go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM=
go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM=
go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc=
golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
@ -528,19 +573,19 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
golang.org/x/image v0.31.0 h1:mLChjE2MV6g1S7oqbXC0/UcKijjm5fnJLUYKIYrLESA=
golang.org/x/image v0.31.0/go.mod h1:R9ec5Lcp96v9FTF+ajwaH3uGxPH4fKfHHAVbUILxghA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -556,10 +601,10 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo=
golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -567,8 +612,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -584,8 +629,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@ -596,8 +641,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@ -608,8 +653,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -617,17 +662,19 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0=
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@ -641,20 +688,22 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/cc/v4 v4.25.2 h1:T2oH7sZdGvTaie0BRNFbIYsabzCxUQg8nLqCdQ2i0ic=
modernc.org/cc/v4 v4.25.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.25.1 h1:TFSzPrAGmDsdnhT9X2UrcPMI3N/mJ9/X9ykKXwLhDsU=
modernc.org/ccgo/v4 v4.25.1/go.mod h1:njjuAYiPflywOOrm3B7kCB444ONP5pAVr8PIEoE0uDw=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM=
modernc.org/cc/v4 v4.26.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
modernc.org/fileutil v1.3.8 h1:qtzNm7ED75pd1C7WgAGcK4edm4fvhtBsEiI/0NQ54YM=
modernc.org/fileutil v1.3.8/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/libc v1.62.1 h1:s0+fv5E3FymN8eJVmnk0llBe6rOxCu/DEU+XygRbS8s=
modernc.org/libc v1.62.1/go.mod h1:iXhATfJQLjG3NWy56a6WVU73lWOcdYVxsvwCgoPljuo=
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ=
modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.9.1 h1:V/Z1solwAVmMW1yttq3nDdZPJqV1rM05Ccq6KMSZ34g=
modernc.org/memory v1.9.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
@ -663,6 +712,8 @@ modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs=
moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE=
mvdan.cc/xurls/v2 v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI=
mvdan.cc/xurls/v2 v2.6.0/go.mod h1:bCvEZ1XvdA6wDnxY7jPPjEmigDtvtvPXAD/Exa9IMSk=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=

View file

@ -49,7 +49,7 @@ func (suite *ActionsTestSuite) SetupSuite() {
func (suite *ActionsTestSuite) TestActionOverlap() {
var (
testStructs = testrig.SetupTestStructs(rMediaPath, rTemplatePath)
ctx = context.Background()
ctx = suite.T().Context()
)
defer testrig.TearDownTestStructs(testStructs)
@ -130,7 +130,7 @@ func (suite *ActionsTestSuite) TestActionOverlap() {
func (suite *ActionsTestSuite) TestActionWithErrors() {
var (
testStructs = testrig.SetupTestStructs(rMediaPath, rTemplatePath)
ctx = context.Background()
ctx = suite.T().Context()
)
defer testrig.TearDownTestStructs(testStructs)

View file

@ -22,7 +22,7 @@ import (
"errors"
"time"
"codeberg.org/gruf/go-kv"
"codeberg.org/gruf/go-kv/v2"
"code.superseriousbusiness.org/gotosocial/internal/ap"
"code.superseriousbusiness.org/gotosocial/internal/config"

View file

@ -23,15 +23,18 @@ import (
"code.superseriousbusiness.org/activity/pub"
)
// PublicURI returns a fresh copy of the *url.URL version of the
// magic ActivityPub URI https://www.w3.org/ns/activitystreams#Public
func PublicURI() *url.URL {
publicURI, err := url.Parse(pub.PublicActivityPubIRI)
// publicIRI is a pre-parsed global public IRI instance.
var publicIRI = func() *url.URL {
url, err := url.Parse(pub.PublicActivityPubIRI)
if err != nil {
panic(err)
}
return publicURI
}
return url
}()
// PublicIRI returns a fresh copy of the *url.URL version of the
// magic ActivityPub URI https://www.w3.org/ns/activitystreams#Public
func PublicIRI() *url.URL { var u url.URL; u = *publicIRI; return &u }
// https://www.w3.org/TR/activitystreams-vocabulary
const (
@ -102,9 +105,12 @@ const (
/* GtS stuff */
ObjectLikeApproval = "LikeApproval"
ObjectReplyApproval = "ReplyApproval"
ObjectAnnounceApproval = "AnnounceApproval"
ActivityLikeRequest = "LikeRequest"
ActivityReplyRequest = "ReplyRequest"
ActivityAnnounceRequest = "AnnounceRequest"
ObjectLikeAuthorization = "LikeAuthorization"
ObjectReplyAuthorization = "ReplyAuthorization"
ObjectAnnounceAuthorization = "AnnounceAuthorization"
/* Funkwhale stuff */
@ -138,7 +144,10 @@ func isActivity(typeName string) bool {
ActivityAnnounce,
ActivityBlock,
ActivityFlag,
ActivityDislike:
ActivityDislike,
ActivityLikeRequest,
ActivityReplyRequest,
ActivityAnnounceRequest:
return true
default:
return false

View file

@ -19,9 +19,9 @@ package ap_test
import (
"bytes"
"context"
"encoding/json"
"io"
"testing"
"code.superseriousbusiness.org/activity/streams"
"code.superseriousbusiness.org/activity/streams/vocab"
@ -110,7 +110,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote {
// Anyone can like.
canLikeAlwaysProp := streams.NewGoToSocialAlwaysProperty()
canLikeAlwaysProp.AppendIRI(ap.PublicURI())
canLikeAlwaysProp.AppendIRI(ap.PublicIRI())
canLike.SetGoToSocialAlways(canLikeAlwaysProp)
// Empty approvalRequired.
@ -127,7 +127,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote {
// Anyone can reply.
canReplyAlwaysProp := streams.NewGoToSocialAlwaysProperty()
canReplyAlwaysProp.AppendIRI(ap.PublicURI())
canReplyAlwaysProp.AppendIRI(ap.PublicIRI())
canReply.SetGoToSocialAlways(canReplyAlwaysProp)
// Set empty approvalRequired.
@ -150,7 +150,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote {
// Public requires approval to announce.
canAnnounceApprovalRequiredProp := streams.NewGoToSocialApprovalRequiredProperty()
canAnnounceApprovalRequiredProp.AppendIRI(ap.PublicURI())
canAnnounceApprovalRequiredProp.AppendIRI(ap.PublicIRI())
canAnnounce.SetGoToSocialApprovalRequired(canAnnounceApprovalRequiredProp)
// Set canAnnounce on the policy.
@ -250,7 +250,7 @@ func (suite *APTestSuite) noteWithHashtags1() ap.Statusable {
}`)
statusable, err := ap.ResolveStatusable(
context.Background(),
suite.T().Context(),
io.NopCloser(bytes.NewReader(noteJson)),
)
if err != nil {
@ -265,7 +265,7 @@ func addressable1() ap.Addressable {
note := streams.NewActivityStreamsNote()
toProp := streams.NewActivityStreamsToProperty()
toProp.AppendIRI(ap.PublicURI())
toProp.AppendIRI(ap.PublicIRI())
note.SetActivityStreamsTo(toProp)
@ -287,7 +287,7 @@ func addressable2() ap.Addressable {
note.SetActivityStreamsTo(toProp)
ccProp := streams.NewActivityStreamsCcProperty()
ccProp.AppendIRI(ap.PublicURI())
ccProp.AppendIRI(ap.PublicIRI())
note.SetActivityStreamsCc(ccProp)
@ -306,7 +306,7 @@ func addressable3() ap.Addressable {
return note
}
func addressable4() vocab.ActivityStreamsAnnounce {
func addressable4(t *testing.T) vocab.ActivityStreamsAnnounce {
// https://codeberg.org/superseriousbusiness/gotosocial/issues/267
announceJson := []byte(`
{
@ -326,12 +326,12 @@ func addressable4() vocab.ActivityStreamsAnnounce {
panic(err)
}
t, err := streams.ToType(context.Background(), jsonAsMap)
typ, err := streams.ToType(t.Context(), jsonAsMap)
if err != nil {
panic(err)
}
return t.(vocab.ActivityStreamsAnnounce)
return typ.(vocab.ActivityStreamsAnnounce)
}
func addressable5() ap.Addressable {
@ -366,7 +366,7 @@ func (suite *APTestSuite) jsonToType(rawJson string) (vocab.Type, map[string]int
panic(err)
}
t, err := streams.ToType(context.Background(), raw)
t, err := streams.ToType(suite.T().Context(), raw)
if err != nil {
panic(err)
}
@ -395,7 +395,7 @@ func (suite *APTestSuite) SetupTest() {
suite.addressable1 = addressable1()
suite.addressable2 = addressable2()
suite.addressable3 = addressable3()
suite.addressable4 = addressable4()
suite.addressable4 = addressable4(suite.T())
suite.addressable5 = addressable5()
suite.testAccounts = testrig.NewTestAccounts()
}

View file

@ -36,7 +36,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/util"
)
// ExtractObjects will extract object vocab.Types from given implementing interface.
// ExtractObjects will extract object TypeOrIRIs from given implementing interface.
func ExtractObjects(with WithObject) []TypeOrIRI {
// Extract the attached object (if any).
objProp := with.GetActivityStreamsObject()
@ -58,6 +58,28 @@ func ExtractObjects(with WithObject) []TypeOrIRI {
return objs
}
// ExtractInstrument will extract instrument TypeOrIRIs from given implementing interface.
func ExtractInstruments(with WithInstrument) []TypeOrIRI {
// Extract the attached instrument (if any).
instrProp := with.GetActivityStreamsInstrument()
if instrProp == nil {
return nil
}
// Check for invalid len.
if instrProp.Len() == 0 {
return nil
}
// Accumulate all of the instruments into a slice.
instrs := make([]TypeOrIRI, instrProp.Len())
for i := range instrProp.Len() {
instrs[i] = instrProp.At(i)
}
return instrs
}
// ExtractActivityData will extract the usable data type (e.g. Note, Question, etc) and corresponding JSON, from activity.
func ExtractActivityData(activity pub.Activity, rawJSON map[string]any) ([]TypeOrIRI, []any, bool) {
switch typeName := activity.GetTypeName(); {
@ -97,11 +119,12 @@ func ExtractActivityData(activity pub.Activity, rawJSON map[string]any) ([]TypeO
func ExtractAccountables(arr []TypeOrIRI) ([]Accountable, []TypeOrIRI) {
var accounts []Accountable
for i := 0; i < len(arr); i++ {
for i := 0; i < len(arr); {
elem := arr[i]
if elem.IsIRI() {
// skip IRIs
i++ // iter
continue
}
@ -112,6 +135,7 @@ func ExtractAccountables(arr []TypeOrIRI) ([]Accountable, []TypeOrIRI) {
// Try cast AS type as Accountable.
account, ok := ToAccountable(t)
if !ok {
i++ // iter
continue
}
@ -130,11 +154,12 @@ func ExtractAccountables(arr []TypeOrIRI) ([]Accountable, []TypeOrIRI) {
func ExtractStatusables(arr []TypeOrIRI) ([]Statusable, []TypeOrIRI) {
var statuses []Statusable
for i := 0; i < len(arr); i++ {
for i := 0; i < len(arr); {
elem := arr[i]
if elem.IsIRI() {
// skip IRIs
i++ // iter
continue
}
@ -145,10 +170,11 @@ func ExtractStatusables(arr []TypeOrIRI) ([]Statusable, []TypeOrIRI) {
// Try cast AS type as Statusable.
status, ok := ToStatusable(t)
if !ok {
i++ // iter
continue
}
// Add casted Statusable type.
// Append casted Statusable type.
statuses = append(statuses, status)
// Drop elem from slice.
@ -163,11 +189,12 @@ func ExtractStatusables(arr []TypeOrIRI) ([]Statusable, []TypeOrIRI) {
func ExtractPollOptionables(arr []TypeOrIRI) ([]PollOptionable, []TypeOrIRI) {
var options []PollOptionable
for i := 0; i < len(arr); i++ {
for i := 0; i < len(arr); {
elem := arr[i]
if elem.IsIRI() {
// skip IRIs
i++ // iter
continue
}
@ -178,6 +205,7 @@ func ExtractPollOptionables(arr []TypeOrIRI) ([]PollOptionable, []TypeOrIRI) {
// Try cast as PollOptionable.
option, ok := ToPollOptionable(t)
if !ok {
i++ // iter
continue
}
@ -357,15 +385,67 @@ func ExtractIconURI(i WithIcon) (*url.URL, error) {
continue
}
imageURL, err := ExtractURL(image)
if err == nil && imageURL != nil {
return imageURL, nil
imageURL := GetURL(image)
if len(imageURL) == 0 {
// Nothing here.
continue
}
// Got a hit.
return imageURL[0], nil
}
return nil, gtserror.New("could not extract valid image URI from icon")
}
// ExtractIconDescription extracts the name property from
// the given WithIcon which links to a supported image file,
// or returns an empty string.
// Input will look something like this:
//
// "icon": {
// "mediaType": "image/jpeg",
// "name": "some description",
// "type": "Image",
// "url": "http://example.org/path/to/some/file.jpeg"
// },
func ExtractIconDescription(i WithIcon) string {
iconProp := i.GetActivityStreamsIcon()
if iconProp == nil {
return ""
}
// Icon can potentially contain multiple entries,
// so we iterate through all of them here in order
// to find the first one that meets these criteria:
//
// 1. Is an image.
// 2. Has a URL that we can use to derefereince it.
for iter := iconProp.Begin(); iter != iconProp.End(); iter = iter.Next() {
if !iter.IsActivityStreamsImage() {
continue
}
image := iter.GetActivityStreamsImage()
if image == nil {
continue
}
imageURL := GetURL(image)
if len(imageURL) == 0 {
// Nothing here.
continue
}
imageDescription := ExtractName(image)
// Got a hit.
return imageDescription
}
return ""
}
// ExtractImageURI extracts the first URI it can find from
// the given WithImage which links to a supported image file.
// Input will look something like this:
@ -399,15 +479,67 @@ func ExtractImageURI(i WithImage) (*url.URL, error) {
continue
}
imageURL, err := ExtractURL(image)
if err == nil && imageURL != nil {
return imageURL, nil
imageURL := GetURL(image)
if len(imageURL) == 0 {
// Nothing here.
continue
}
// Got a hit.
return imageURL[0], nil
}
return nil, gtserror.New("could not extract valid image URI from image")
}
// ExtractImageDescription extracts the name property from
// the given WithImage which links to a supported image file,
// or returns an empty string.
// Input will look something like this:
//
// "image": {
// "mediaType": "image/jpeg",
// "name": "some description",
// "type": "Image",
// "url": "http://example.org/path/to/some/file.jpeg"
// },
func ExtractImageDescription(i WithImage) string {
imageProp := i.GetActivityStreamsImage()
if imageProp == nil {
return ""
}
// Image can potentially contain multiple entries,
// so we iterate through all of them here in order
// to find the first one that meets these criteria:
//
// 1. Is an image.
// 2. Has a URL that we can use to derefereince it.
for iter := imageProp.Begin(); iter != imageProp.End(); iter = iter.Next() {
if !iter.IsActivityStreamsImage() {
continue
}
image := iter.GetActivityStreamsImage()
if image == nil {
continue
}
imageURL := GetURL(image)
if len(imageURL) == 0 {
// Nothing here.
continue
}
imageDescription := ExtractName(image)
// Got a hit.
return imageDescription
}
return ""
}
// ExtractSummary extracts the summary/content warning of
// the given WithSummary interface. Will return an empty
// string if no summary/content warning was present.
@ -488,28 +620,6 @@ func ExtractFields(i WithAttachment) []*gtsmodel.Field {
return fields
}
// ExtractURL extracts the first URI it can find from the
// given WithURL interface, or an error if no URL was set.
// The ID of a type will not work, this function wants a URI
// specifically.
func ExtractURL(i WithURL) (*url.URL, error) {
urlProp := i.GetActivityStreamsUrl()
if urlProp == nil {
return nil, gtserror.New("url property was nil")
}
for iter := urlProp.Begin(); iter != urlProp.End(); iter = iter.Next() {
if !iter.IsIRI() {
continue
}
// Found it.
return iter.GetIRI(), nil
}
return nil, gtserror.New("no valid URL property found")
}
// ExtractPubKeyFromActor extracts the public key, public key ID, and public
// key owner ID from an interface, or an error if something goes wrong.
func ExtractPubKeyFromActor(i WithPublicKey) (
@ -634,32 +744,38 @@ func ExtractContent(i WithContent) gtsmodel.Content {
return content
}
// ExtractAttachments attempts to extract barebones MediaAttachment objects from given AS interface type.
// ExtractAttachments attempts to extract barebones
// MediaAttachment objects from given AS interface type.
func ExtractAttachments(i WithAttachment) ([]*gtsmodel.MediaAttachment, error) {
attachmentProp := i.GetActivityStreamsAttachment()
if attachmentProp == nil {
return nil, nil
}
var errs gtserror.MultiError
var (
attachments = make([]*gtsmodel.MediaAttachment, 0, attachmentProp.Len())
errs gtserror.MultiError
)
attachments := make([]*gtsmodel.MediaAttachment, 0, attachmentProp.Len())
for iter := attachmentProp.Begin(); iter != attachmentProp.End(); iter = iter.Next() {
t := iter.GetType()
if t == nil {
errs.Appendf("nil attachment type")
continue
}
attachmentable, ok := t.(Attachmentable)
attachmentable, ok := ToAttachmentable(t)
if !ok {
errs.Appendf("incorrect attachment type: %T", t)
errs.Appendf("could not cast %T to Attachmentable", t)
continue
}
attachment, err := ExtractAttachment(attachmentable)
if err != nil {
errs.Appendf("error extracting attachment: %w", err)
continue
}
attachments = append(attachments, attachment)
}
@ -670,18 +786,21 @@ func ExtractAttachments(i WithAttachment) ([]*gtsmodel.MediaAttachment, error) {
// (just remote URL, description, and blurhash) from the given
// Attachmentable interface, or an error if no remote URL is set.
func ExtractAttachment(i Attachmentable) (*gtsmodel.MediaAttachment, error) {
// Get the URL for the attachment file.
// Get the first URL for the attachment file.
// If no URL is set, we can't do anything.
remoteURL, err := ExtractURL(i)
if err != nil {
return nil, gtserror.Newf("error extracting attachment URL: %w", err)
remoteURL := GetURL(i)
if len(remoteURL) == 0 {
return nil, gtserror.New("empty attachment URL")
}
return &gtsmodel.MediaAttachment{
RemoteURL: remoteURL.String(),
RemoteURL: remoteURL[0].String(),
Description: ExtractDescription(i),
Blurhash: ExtractBlurhash(i),
Processing: gtsmodel.ProcessingStatusReceived,
FileMeta: gtsmodel.FileMeta{
Focus: ExtractFocus(i),
},
Processing: gtsmodel.ProcessingStatusReceived,
}, nil
}
@ -708,6 +827,50 @@ func ExtractBlurhash(i WithBlurhash) string {
return blurhashProp.Get()
}
// ExtractFocus parses a gtsmodel.Focus from the given Attachmentable's
// `focalPoint` property, if Attachmentable can have `focalPoint`, and
// `focalPoint` is set to a valid pair of floats. Otherwise, returns a
// zero gtsmodel.Focus (ie., focus in the centre of the image).
func ExtractFocus(attachmentable Attachmentable) gtsmodel.Focus {
focus := gtsmodel.Focus{}
withFocalPoint, ok := attachmentable.(WithFocalPoint)
if !ok {
return focus
}
focalPointProp := withFocalPoint.GetTootFocalPoint()
if focalPointProp == nil || focalPointProp.Len() != 2 {
return focus
}
xProp := focalPointProp.At(0)
if !xProp.IsXMLSchemaFloat() {
return focus
}
yProp := focalPointProp.At(1)
if !yProp.IsXMLSchemaFloat() {
return focus
}
x := xProp.Get()
if x < -1 || x > 1 {
return focus
}
y := yProp.Get()
if y < -1 || y > 1 {
return focus
}
// Looks good.
focus.X = float32(x)
focus.Y = float32(y)
return focus
}
// ExtractHashtags extracts a slice of minimal gtsmodel.Tags
// from a WithTag. If an entry in the WithTag is not a hashtag,
// or has a name that cannot be normalized, it will be ignored.
@ -1074,18 +1237,21 @@ func ExtractVisibility(addressable Addressable, actorFollowersURI string) (gtsmo
// Will be nil (default policy) for Statusables that have no policy
// set on them, or have a null policy. In such a case, the caller
// should assume the default policy for the status's visibility level.
//
// Sub-policies of the returned policy, eg., CanLike, CanReply, may
// each be nil if they were not set on the interaction policy.
func ExtractInteractionPolicy(
statusable Statusable,
owner *gtsmodel.Account,
) *gtsmodel.InteractionPolicy {
ipa, ok := statusable.(InteractionPolicyAware)
wip, ok := statusable.(WithInteractionPolicy)
if !ok {
// Not a type with interaction
// policy properties settable.
return nil
}
policyProp := ipa.GetGoToSocialInteractionPolicy()
policyProp := wip.GetGoToSocialInteractionPolicy()
if policyProp == nil || policyProp.Len() != 1 {
return nil
}
@ -1100,6 +1266,8 @@ func ExtractInteractionPolicy(
return nil
}
// There's a policy key/value
// set, extract sub-policies.
return &gtsmodel.InteractionPolicy{
CanLike: extractCanLike(policy.GetGoToSocialCanLike(), owner),
CanReply: extractCanReply(policy.GetGoToSocialCanReply(), owner),
@ -1107,75 +1275,104 @@ func ExtractInteractionPolicy(
}
}
// Returns either a parsed CanLike sub-policy, or nil
// if canLike is not set, ie., if this post is from an
// instance that doesn't know / care about canLike.
func extractCanLike(
prop vocab.GoToSocialCanLikeProperty,
owner *gtsmodel.Account,
) gtsmodel.PolicyRules {
) *gtsmodel.PolicyRules {
if prop == nil || prop.Len() != 1 {
return gtsmodel.PolicyRules{}
return nil
}
propIter := prop.At(0)
if !propIter.IsGoToSocialCanLike() {
return gtsmodel.PolicyRules{}
return nil
}
withRules := propIter.Get()
if withRules == nil {
return gtsmodel.PolicyRules{}
return nil
}
return gtsmodel.PolicyRules{
Always: extractPolicyValues(withRules.GetGoToSocialAlways(), owner),
WithApproval: extractPolicyValues(withRules.GetGoToSocialApprovalRequired(), owner),
}
return extractPolicyRules(withRules, owner)
}
// Returns either a parsed CanReply sub-policy, or nil
// if canReply is not set, ie., if this post is from an
// instance that doesn't know / care about canReply.
func extractCanReply(
prop vocab.GoToSocialCanReplyProperty,
owner *gtsmodel.Account,
) gtsmodel.PolicyRules {
) *gtsmodel.PolicyRules {
if prop == nil || prop.Len() != 1 {
return gtsmodel.PolicyRules{}
return nil
}
propIter := prop.At(0)
if !propIter.IsGoToSocialCanReply() {
return gtsmodel.PolicyRules{}
return nil
}
withRules := propIter.Get()
if withRules == nil {
return gtsmodel.PolicyRules{}
return nil
}
return gtsmodel.PolicyRules{
Always: extractPolicyValues(withRules.GetGoToSocialAlways(), owner),
WithApproval: extractPolicyValues(withRules.GetGoToSocialApprovalRequired(), owner),
}
return extractPolicyRules(withRules, owner)
}
// Returns either a parsed CanAnnounce sub-policy, or nil
// if canAnnounce is not set, ie., if this post is from an
// instance that doesn't know / care about canAnnounce.
func extractCanAnnounce(
prop vocab.GoToSocialCanAnnounceProperty,
owner *gtsmodel.Account,
) gtsmodel.PolicyRules {
) *gtsmodel.PolicyRules {
if prop == nil || prop.Len() != 1 {
return gtsmodel.PolicyRules{}
return nil
}
propIter := prop.At(0)
if !propIter.IsGoToSocialCanAnnounce() {
return gtsmodel.PolicyRules{}
return nil
}
withRules := propIter.Get()
if withRules == nil {
return gtsmodel.PolicyRules{}
return nil
}
return gtsmodel.PolicyRules{
Always: extractPolicyValues(withRules.GetGoToSocialAlways(), owner),
WithApproval: extractPolicyValues(withRules.GetGoToSocialApprovalRequired(), owner),
return extractPolicyRules(withRules, owner)
}
func extractPolicyRules(
withRules WithPolicyRules,
owner *gtsmodel.Account,
) *gtsmodel.PolicyRules {
// Check for `automaticApproval` and
// `manualApproval` properties first.
var (
automaticApproval = withRules.GetGoToSocialAutomaticApproval()
manualApproval = withRules.GetGoToSocialManualApproval()
)
if (automaticApproval != nil && automaticApproval.Len() != 0) ||
(manualApproval != nil && manualApproval.Len() != 0) {
// At least one is set, use these props.
return &gtsmodel.PolicyRules{
AutomaticApproval: extractPolicyValues(automaticApproval, owner),
ManualApproval: extractPolicyValues(manualApproval, owner),
}
}
// Fall back to deprecated `always`
// and `withApproval` properties.
//
// TODO: Remove this in GtS v0.21.0.
return &gtsmodel.PolicyRules{
AutomaticApproval: extractPolicyValues(withRules.GetGoToSocialAlways(), owner),
ManualApproval: extractPolicyValues(withRules.GetGoToSocialApprovalRequired(), owner),
}
}

View file

@ -18,7 +18,6 @@
package ap_test
import (
"context"
"encoding/json"
"testing"
@ -36,7 +35,7 @@ func (suite *ExtractAttachmentsTestSuite) TestExtractAttachmentMissingURL() {
d1.SetActivityStreamsUrl(streams.NewActivityStreamsUrlProperty())
attachment, err := ap.ExtractAttachment(d1)
suite.EqualError(err, "ExtractAttachment: error extracting attachment URL: ExtractURL: no valid URL property found")
suite.EqualError(err, "ExtractAttachment: empty attachment URL")
suite.Nil(attachment)
}
@ -59,7 +58,7 @@ func (suite *ExtractAttachmentsTestSuite) TestExtractDescription() {
suite.FailNow(err.Error())
}
t, err := streams.ToType(context.Background(), raw)
t, err := streams.ToType(suite.T().Context(), raw)
if err != nil {
suite.FailNow(err.Error())
}

View file

@ -19,7 +19,6 @@ package ap_test
import (
"bytes"
"context"
"io"
"testing"
@ -61,7 +60,7 @@ func (suite *ExtractEmojisTestSuite) TestExtractEmojis() {
}`
statusable, err := ap.ResolveStatusable(
context.Background(),
suite.T().Context(),
io.NopCloser(bytes.NewBufferString(noteWithEmojis)),
)
if err != nil {
@ -115,7 +114,7 @@ func (suite *ExtractEmojisTestSuite) TestExtractEmojisNoID() {
}`
statusable, err := ap.ResolveStatusable(
context.Background(),
suite.T().Context(),
io.NopCloser(bytes.NewBufferString(noteWithEmojis)),
)
if err != nil {
@ -170,7 +169,7 @@ func (suite *ExtractEmojisTestSuite) TestExtractEmojisNullID() {
}`
statusable, err := ap.ResolveStatusable(
context.Background(),
suite.T().Context(),
io.NopCloser(bytes.NewBufferString(noteWithEmojis)),
)
if err != nil {
@ -225,7 +224,7 @@ func (suite *ExtractEmojisTestSuite) TestExtractEmojisEmptyID() {
}`
statusable, err := ap.ResolveStatusable(
context.Background(),
suite.T().Context(),
io.NopCloser(bytes.NewBufferString(noteWithEmojis)),
)
if err != nil {

View file

@ -0,0 +1,124 @@
// GoToSocial
// Copyright (C) GoToSocial Authors admin@gotosocial.org
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package ap_test
import (
"encoding/json"
"fmt"
"testing"
"code.superseriousbusiness.org/activity/streams"
"code.superseriousbusiness.org/gotosocial/internal/ap"
"github.com/stretchr/testify/suite"
)
type ExtractFocusTestSuite struct {
APTestSuite
}
func (suite *ExtractFocusTestSuite) TestExtractFocus() {
ctx := suite.T().Context()
type test struct {
data string
expectX float32
expectY float32
}
for _, test := range []test{
{
// Fine.
data: "-0.5, 0.5",
expectX: -0.5,
expectY: 0.5,
},
{
// Also fine.
data: "1, 1",
expectX: 1,
expectY: 1,
},
{
// Out of range.
data: "1.5, 1",
expectX: 0,
expectY: 0,
},
{
// Too many points.
data: "1, 1, 0",
expectX: 0,
expectY: 0,
},
{
// Not enough points.
data: "1",
expectX: 0,
expectY: 0,
},
} {
// Wrap provided test.data
// in a minimal Attachmentable.
const fmts = `{
"@context": [
"https://www.w3.org/ns/activitystreams",
{
"focalPoint": {
"@container": "@list",
"@id": "toot:focalPoint"
},
"toot": "http://joinmastodon.org/ns#"
}
],
"focalPoint": [ %s ],
"type": "Image"
}`
// Unmarshal test data.
data := fmt.Sprintf(fmts, test.data)
m := make(map[string]any)
if err := json.Unmarshal([]byte(data), &m); err != nil {
suite.FailNow(err.Error())
}
// Convert to type.
t, err := streams.ToType(ctx, m)
if err != nil {
suite.FailNow(err.Error())
}
// Convert to attachmentable.
attachmentable, ok := t.(ap.Attachmentable)
if !ok {
suite.FailNow("", "%T was not Attachmentable", t)
}
// Check extracted focus.
focus := ap.ExtractFocus(attachmentable)
if focus.X != test.expectX || focus.Y != test.expectY {
suite.Fail("",
"expected x=%.2f y=%.2f got x=%.2f y=%.2f",
test.expectX, test.expectY, focus.X, focus.Y,
)
}
}
}
func TestExtractFocusTestSuite(t *testing.T) {
suite.Run(t, new(ExtractFocusTestSuite))
}

View file

@ -19,7 +19,6 @@ package ap_test
import (
"bytes"
"context"
"io"
"testing"
@ -43,6 +42,174 @@ func (suite *ExtractPolicyTestSuite) TestExtractPolicy() {
"en": "hey @f0x and @dumpsterqueer",
"fr": "bonjour @f0x et @dumpsterqueer"
},
"interactionPolicy": {
"canLike": {
"automaticApproval": [
"https://www.w3.org/ns/activitystreams#Public"
],
"manualApproval": []
},
"canReply": {
"automaticApproval": [
"http://localhost:8080/users/the_mighty_zork",
"http://localhost:8080/users/the_mighty_zork/followers",
"https://gts.superseriousbusiness.org/users/dumpsterqueer",
"https://gts.superseriousbusiness.org/users/f0x"
],
"manualApproval": [
"https://www.w3.org/ns/activitystreams#Public"
]
},
"canAnnounce": {
"automaticApproval": [
"http://localhost:8080/users/the_mighty_zork"
],
"manualApproval": [
"https://www.w3.org/ns/activitystreams#Public"
]
}
},
"tag": [
{
"href": "https://gts.superseriousbusiness.org/users/dumpsterqueer",
"name": "@dumpsterqueer@superseriousbusiness.org",
"type": "Mention"
},
{
"href": "https://gts.superseriousbusiness.org/users/f0x",
"name": "@f0x@superseriousbusiness.org",
"type": "Mention"
}
],
"type": "Note"
}`
statusable, err := ap.ResolveStatusable(
suite.T().Context(),
io.NopCloser(
bytes.NewBufferString(rawNote),
),
)
if err != nil {
suite.FailNow(err.Error())
}
policy := ap.ExtractInteractionPolicy(
statusable,
// Zork didn't actually create
// this status but nevermind.
suite.testAccounts["local_account_1"],
)
expectedPolicy := &gtsmodel.InteractionPolicy{
CanLike: &gtsmodel.PolicyRules{
AutomaticApproval: gtsmodel.PolicyValues{
gtsmodel.PolicyValuePublic,
},
ManualApproval: gtsmodel.PolicyValues{},
},
CanReply: &gtsmodel.PolicyRules{
AutomaticApproval: gtsmodel.PolicyValues{
gtsmodel.PolicyValueAuthor,
gtsmodel.PolicyValueFollowers,
"https://gts.superseriousbusiness.org/users/dumpsterqueer",
"https://gts.superseriousbusiness.org/users/f0x",
},
ManualApproval: gtsmodel.PolicyValues{
gtsmodel.PolicyValuePublic,
},
},
CanAnnounce: &gtsmodel.PolicyRules{
AutomaticApproval: gtsmodel.PolicyValues{
gtsmodel.PolicyValueAuthor,
},
ManualApproval: gtsmodel.PolicyValues{
gtsmodel.PolicyValuePublic,
},
},
}
suite.EqualValues(expectedPolicy, policy)
}
func (suite *ExtractPolicyTestSuite) TestExtractPolicyUnsetProps() {
rawNote := `{
"@context": [
"https://gotosocial.org/ns",
"https://www.w3.org/ns/activitystreams"
],
"content": "hey @f0x and @dumpsterqueer",
"contentMap": {
"en": "hey @f0x and @dumpsterqueer",
"fr": "bonjour @f0x et @dumpsterqueer"
},
"interactionPolicy": {
"canAnnounce": {
"automaticApproval": [
"http://localhost:8080/users/the_mighty_zork"
],
"manualApproval": [
"https://www.w3.org/ns/activitystreams#Public"
]
}
},
"tag": [
{
"href": "https://gts.superseriousbusiness.org/users/dumpsterqueer",
"name": "@dumpsterqueer@superseriousbusiness.org",
"type": "Mention"
},
{
"href": "https://gts.superseriousbusiness.org/users/f0x",
"name": "@f0x@superseriousbusiness.org",
"type": "Mention"
}
],
"type": "Note"
}`
statusable, err := ap.ResolveStatusable(
suite.T().Context(),
io.NopCloser(
bytes.NewBufferString(rawNote),
),
)
if err != nil {
suite.FailNow(err.Error())
}
policy := ap.ExtractInteractionPolicy(
statusable,
// Zork didn't actually create
// this status but nevermind.
suite.testAccounts["local_account_1"],
)
expectedPolicy := &gtsmodel.InteractionPolicy{
CanLike: nil,
CanReply: nil,
CanAnnounce: &gtsmodel.PolicyRules{
AutomaticApproval: gtsmodel.PolicyValues{
gtsmodel.PolicyValueAuthor,
},
ManualApproval: gtsmodel.PolicyValues{
gtsmodel.PolicyValuePublic,
},
},
}
suite.EqualValues(expectedPolicy, policy)
}
func (suite *ExtractPolicyTestSuite) TestExtractPolicyDeprecated() {
rawNote := `{
"@context": [
"https://gotosocial.org/ns",
"https://www.w3.org/ns/activitystreams"
],
"content": "hey @f0x and @dumpsterqueer",
"contentMap": {
"en": "hey @f0x and @dumpsterqueer",
"fr": "bonjour @f0x et @dumpsterqueer"
},
"interactionPolicy": {
"canLike": {
"always": [
@ -86,7 +253,7 @@ func (suite *ExtractPolicyTestSuite) TestExtractPolicy() {
}`
statusable, err := ap.ResolveStatusable(
context.Background(),
suite.T().Context(),
io.NopCloser(
bytes.NewBufferString(rawNote),
),
@ -103,28 +270,28 @@ func (suite *ExtractPolicyTestSuite) TestExtractPolicy() {
)
expectedPolicy := &gtsmodel.InteractionPolicy{
CanLike: gtsmodel.PolicyRules{
Always: gtsmodel.PolicyValues{
CanLike: &gtsmodel.PolicyRules{
AutomaticApproval: gtsmodel.PolicyValues{
gtsmodel.PolicyValuePublic,
},
WithApproval: gtsmodel.PolicyValues{},
ManualApproval: gtsmodel.PolicyValues{},
},
CanReply: gtsmodel.PolicyRules{
Always: gtsmodel.PolicyValues{
CanReply: &gtsmodel.PolicyRules{
AutomaticApproval: gtsmodel.PolicyValues{
gtsmodel.PolicyValueAuthor,
gtsmodel.PolicyValueFollowers,
"https://gts.superseriousbusiness.org/users/dumpsterqueer",
"https://gts.superseriousbusiness.org/users/f0x",
},
WithApproval: gtsmodel.PolicyValues{
ManualApproval: gtsmodel.PolicyValues{
gtsmodel.PolicyValuePublic,
},
},
CanAnnounce: gtsmodel.PolicyRules{
Always: gtsmodel.PolicyValues{
CanAnnounce: &gtsmodel.PolicyRules{
AutomaticApproval: gtsmodel.PolicyValues{
gtsmodel.PolicyValueAuthor,
},
WithApproval: gtsmodel.PolicyValues{
ManualApproval: gtsmodel.PolicyValues{
gtsmodel.PolicyValuePublic,
},
},

View file

@ -18,7 +18,6 @@
package ap_test
import (
"context"
"encoding/json"
"testing"
@ -62,7 +61,7 @@ func (suite *ExtractPubKeyTestSuite) TestExtractPubKeyFromStub() {
suite.FailNow(err.Error())
}
t, err := streams.ToType(context.Background(), m)
t, err := streams.ToType(suite.T().Context(), m)
if err != nil {
suite.FailNow(err.Error())
}

View file

@ -143,13 +143,13 @@ func ToAcceptable(t vocab.Type) (Acceptable, bool) {
return acceptable, true
}
// IsApprovable returns whether AS vocab type name
// is something that can be cast to Approvable.
func IsApprovable(typeName string) bool {
// IsAuthorizationable returns whether AS vocab type name
// is something that can be cast to Authorizationable.
func IsAuthorizationable(typeName string) bool {
switch typeName {
case ObjectLikeApproval,
ObjectReplyApproval,
ObjectAnnounceApproval:
case ObjectLikeAuthorization,
ObjectReplyAuthorization,
ObjectAnnounceAuthorization:
return true
default:
return false
@ -157,12 +157,65 @@ func IsApprovable(typeName string) bool {
}
// ToAcceptable safely tries to cast vocab.Type as Approvable.
func ToApprovable(t vocab.Type) (Approvable, bool) {
approvable, ok := t.(Approvable)
if !ok || !IsApprovable(t.GetTypeName()) {
func ToAuthorizationable(t vocab.Type) (Authorizationable, bool) {
authable, ok := t.(Authorizationable)
if !ok || !IsAuthorizationable(t.GetTypeName()) {
return nil, false
}
return approvable, true
return authable, true
}
// IsAttachmentable returns whether AS vocab type name
// is something that can be cast to Attachmentable.
func IsAttachmentable(typeName string) bool {
switch typeName {
case ObjectAudio,
ObjectDocument,
ObjectImage,
ObjectVideo:
return true
default:
return false
}
}
// ToAttachmentable safely tries to cast vocab.Type as Attachmentable.
func ToAttachmentable(t vocab.Type) (Attachmentable, bool) {
attachmentable, ok := t.(Attachmentable)
if !ok || !IsAttachmentable(t.GetTypeName()) {
return nil, false
}
return attachmentable, true
}
// IsAnnounceable returns whether AS vocab type name
// is something that can be cast to vocab.ActivityStreamsAnnounce.
func IsAnnounceable(typeName string) bool {
return typeName == ActivityAnnounce
}
// ToAnnounceable safely tries to cast vocab.Type as vocab.ActivityStreamsAnnounce.
func ToAnnounceable(t vocab.Type) (vocab.ActivityStreamsAnnounce, bool) {
announceable, ok := t.(vocab.ActivityStreamsAnnounce)
if !ok || t.GetTypeName() != ActivityAnnounce {
return nil, false
}
return announceable, true
}
// IsLikeable returns whether AS vocab type name
// is something that can be cast to vocab.ActivityStreamsLike.
func IsLikeable(typeName string) bool {
return typeName == ActivityLike
}
// ToAnnouncToLikeableeable safely tries to cast vocab.Type as vocab.ActivityStreamsLike.
func ToLikeable(t vocab.Type) (vocab.ActivityStreamsLike, bool) {
likeable, ok := t.(vocab.ActivityStreamsLike)
if !ok || t.GetTypeName() != ActivityLike {
return nil, false
}
return likeable, true
}
// Activityable represents the minimum activitypub interface for representing an 'activity'.
@ -204,6 +257,8 @@ type Accountable interface {
WithMovedTo
WithAlsoKnownAs
WithManuallyApprovesFollowers
WithHidesToPublicFromUnauthedWeb
WithHidesCcPublicFromUnauthedWeb
WithEndpoints
WithTag
WithPublished
@ -233,11 +288,6 @@ type Statusable interface {
WithReplies
}
type InteractionPolicyAware interface {
WithInteractionPolicy
WithApprovedBy
}
// Pollable represents the minimum activitypub interface for representing a 'poll' (it's a subset of a status).
// (see: IsPollable() for types implementing this, though you MUST make sure to check
// the typeName as this bare interface may be implementable by non-Pollable types).
@ -274,14 +324,14 @@ type Acceptable interface {
WithResult
}
// Approvable represents the minimum activitypub interface
// for a LikeApproval, ReplyApproval, or AnnounceApproval.
type Approvable interface {
// Authorizationable represents the minimum interface for a
// LikeAuthorization, ReplyAuthorization, AnnounceAuthorization.
type Authorizationable interface {
vocab.Type
WithAttributedTo
WithObject
WithTarget
WithInteractingObject
WithInteractionTarget
}
// Attachmentable represents the minimum activitypub interface for representing a 'mediaAttachment'. (see: IsAttachmentable).
@ -367,6 +417,16 @@ type ReplyToable interface {
WithInReplyTo
}
// InteractionRequestable represents the minimum interface for an interaction request
// activity, eg., LikeRequest, ReplyRequest, AnnounceRequest, QuoteRequest, etc..
type InteractionRequestable interface {
vocab.Type
WithActor
WithObject
WithInstrument
}
// CollectionIterator represents the minimum interface for interacting with a
// wrapped Collection or OrderedCollection in order to access next / prev items.
type CollectionIterator interface {
@ -628,9 +688,11 @@ type WithBlurhash interface {
SetTootBlurhash(vocab.TootBlurhashProperty)
}
// type withFocalPoint interface {
// // TODO
// }
// WithFocalPoint represents an object with TootFocalPointProperty.
type WithFocalPoint interface {
GetTootFocalPoint() vocab.TootFocalPointProperty
SetTootFocalPoint(vocab.TootFocalPointProperty)
}
// WithHref represents an activity with ActivityStreamsHrefProperty
type WithHref interface {
@ -656,6 +718,12 @@ type WithObject interface {
SetActivityStreamsObject(vocab.ActivityStreamsObjectProperty)
}
// WithInstrument represents an activity with ActivityStreamsInstrumentProperty
type WithInstrument interface {
GetActivityStreamsInstrument() vocab.ActivityStreamsInstrumentProperty
SetActivityStreamsInstrument(vocab.ActivityStreamsInstrumentProperty)
}
// WithTarget represents an activity with ActivityStreamsTargetProperty
type WithTarget interface {
GetActivityStreamsTarget() vocab.ActivityStreamsTargetProperty
@ -686,6 +754,18 @@ type WithManuallyApprovesFollowers interface {
SetActivityStreamsManuallyApprovesFollowers(vocab.ActivityStreamsManuallyApprovesFollowersProperty)
}
// WithHidesToPublicFromUnauthedWeb represents a Person or profile with the hidesToPublicFromUnauthedWeb property.
type WithHidesToPublicFromUnauthedWeb interface {
GetGoToSocialHidesToPublicFromUnauthedWeb() vocab.GoToSocialHidesToPublicFromUnauthedWebProperty
SetGoToSocialHidesToPublicFromUnauthedWeb(vocab.GoToSocialHidesToPublicFromUnauthedWebProperty)
}
// WithHidesCcPublicFromUnauthedWeb represents a Person or profile with the hidesCcPublicFromUnauthedWeb property.
type WithHidesCcPublicFromUnauthedWeb interface {
GetGoToSocialHidesCcPublicFromUnauthedWeb() vocab.GoToSocialHidesCcPublicFromUnauthedWebProperty
SetGoToSocialHidesCcPublicFromUnauthedWeb(vocab.GoToSocialHidesCcPublicFromUnauthedWebProperty)
}
// WithEndpoints represents a Person or profile with the endpoints property
type WithEndpoints interface {
GetActivityStreamsEndpoints() vocab.ActivityStreamsEndpointsProperty
@ -730,18 +810,50 @@ type WithInteractionPolicy interface {
// WithPolicyRules represents an activity with always and approvalRequired properties.
type WithPolicyRules interface {
GetGoToSocialAlways() vocab.GoToSocialAlwaysProperty
GetGoToSocialApprovalRequired() vocab.GoToSocialApprovalRequiredProperty
GetGoToSocialAutomaticApproval() vocab.GoToSocialAutomaticApprovalProperty
GetGoToSocialManualApproval() vocab.GoToSocialManualApprovalProperty
GetGoToSocialAlways() vocab.GoToSocialAlwaysProperty // Deprecated
GetGoToSocialApprovalRequired() vocab.GoToSocialApprovalRequiredProperty // Deprecated
}
// WithApprovedBy represents a Statusable with the approvedBy property.
// WithApprovedBy represents an object with the approvedBy property.
type WithApprovedBy interface {
GetGoToSocialApprovedBy() vocab.GoToSocialApprovedByProperty
SetGoToSocialApprovedBy(vocab.GoToSocialApprovedByProperty)
}
// WithVotersCount represents an activity or object the result property.
// WithLikeAuthorization represents a Likeable with the likeAuthorization property.
type WithLikeAuthorization interface {
GetGoToSocialLikeAuthorization() vocab.GoToSocialLikeAuthorizationProperty
SetGoToSocialLikeAuthorization(vocab.GoToSocialLikeAuthorizationProperty)
}
// WithReplyAuthorization represents a statusable with the replyAuthorization property.
type WithReplyAuthorization interface {
GetGoToSocialReplyAuthorization() vocab.GoToSocialReplyAuthorizationProperty
SetGoToSocialReplyAuthorization(vocab.GoToSocialReplyAuthorizationProperty)
}
// WithAnnounceAuthorization represents an Announceable with the announceAuthorization property.
type WithAnnounceAuthorization interface {
GetGoToSocialAnnounceAuthorization() vocab.GoToSocialAnnounceAuthorizationProperty
SetGoToSocialAnnounceAuthorization(vocab.GoToSocialAnnounceAuthorizationProperty)
}
// WithResult represents an activity or object with the result property.
type WithResult interface {
GetActivityStreamsResult() vocab.ActivityStreamsResultProperty
SetActivityStreamsResult(vocab.ActivityStreamsResultProperty)
}
// WithInteractingObject represents an activity or object with the InteractingObject property.
type WithInteractingObject interface {
GetGoToSocialInteractingObject() vocab.GoToSocialInteractingObjectProperty
SetGoToSocialInteractingObject(vocab.GoToSocialInteractingObjectProperty)
}
// WithInteractionTarget represents an activity or object with the InteractionTarget property.
type WithInteractionTarget interface {
GetGoToSocialInteractionTarget() vocab.GoToSocialInteractionTargetProperty
SetGoToSocialInteractionTarget(vocab.GoToSocialInteractionTargetProperty)
}

View file

@ -582,16 +582,16 @@ func NormalizeOutgoingContentProp(item WithContent, rawJSON map[string]interface
//
// "interactionPolicy": {
// "canAnnounce": {
// "always": "https://www.w3.org/ns/activitystreams#Public",
// "approvalRequired": []
// "automaticApproval": "https://www.w3.org/ns/activitystreams#Public",
// "manualApproval": []
// },
// "canLike": {
// "always": "https://www.w3.org/ns/activitystreams#Public",
// "approvalRequired": []
// "automaticApproval": "https://www.w3.org/ns/activitystreams#Public",
// "manualApproval": []
// },
// "canReply": {
// "always": "https://www.w3.org/ns/activitystreams#Public",
// "approvalRequired": []
// "automaticApproval": "https://www.w3.org/ns/activitystreams#Public",
// "manualApproval": []
// }
// }
//
@ -599,22 +599,22 @@ func NormalizeOutgoingContentProp(item WithContent, rawJSON map[string]interface
//
// "interactionPolicy": {
// "canAnnounce": {
// "always": [
// "automaticApproval": [
// "https://www.w3.org/ns/activitystreams#Public"
// ],
// "approvalRequired": []
// "manualApproval": []
// },
// "canLike": {
// "always": [
// "automaticApproval": [
// "https://www.w3.org/ns/activitystreams#Public"
// ],
// "approvalRequired": []
// "manualApproval": []
// },
// "canReply": {
// "always": [
// "automaticApproval": [
// "https://www.w3.org/ns/activitystreams#Public"
// ],
// "approvalRequired": []
// "manualApproval": []
// }
// }
//
@ -655,8 +655,10 @@ func NormalizeOutgoingInteractionPolicyProp(item WithInteractionPolicy, rawJSON
}
for _, PolicyValuesKey := range []string{
"always",
"approvalRequired",
"automaticApproval",
"manualApproval",
"always", // deprecated
"approvalRequired", // deprecated
} {
PolicyValuesVal, ok := rulesValMap[PolicyValuesKey]
if !ok {

View file

@ -135,7 +135,8 @@ func AppendBcc(with WithBcc, bcc ...*url.URL) {
}, bcc...)
}
// GetURL returns the IRIs contained in the URL property of 'with'.
// GetURL returns IRIs contained
// in the URL property of 'with'.
func GetURL(with WithURL) []*url.URL {
urlProp := with.GetActivityStreamsUrl()
if urlProp == nil || urlProp.Len() == 0 {
@ -144,9 +145,31 @@ func GetURL(with WithURL) []*url.URL {
urls := make([]*url.URL, 0, urlProp.Len())
for i := 0; i < urlProp.Len(); i++ {
at := urlProp.At(i)
// See if it's a plain URI.
if at.IsXMLSchemaAnyURI() {
u := at.GetXMLSchemaAnyURI()
urls = append(urls, u)
continue
}
// See if it's a Link obj
// with an href property.
if at.IsActivityStreamsLink() {
l := at.GetActivityStreamsLink()
hr := l.GetActivityStreamsHref()
if hr == nil {
// No href.
continue
}
if hr.IsXMLSchemaAnyURI() {
u := hr.Get()
urls = append(urls, u)
} else if hr.IsIRI() {
u := hr.GetIRI()
urls = append(urls, u)
}
}
}
return urls
@ -203,6 +226,36 @@ func AppendObjectIRIs(with WithObject, object ...*url.URL) {
}, object...)
}
// AppendInstrumentIRIs appends the given IRIs to the Instrument property of 'with'.
func AppendInstrumentIRIs(with WithInstrument, instrument ...*url.URL) {
appendIRIs(func() Property[vocab.ActivityStreamsInstrumentPropertyIterator] {
instrumentProp := with.GetActivityStreamsInstrument()
if instrumentProp == nil {
instrumentProp = streams.NewActivityStreamsInstrumentProperty()
with.SetActivityStreamsInstrument(instrumentProp)
}
return instrumentProp
}, instrument...)
}
// GetResultIRIs returns the IRIs contained in the `result` property of 'with'.
func GetResultIRIs(with WithResult) []*url.URL {
resultProp := with.GetActivityStreamsResult()
return extractIRIs(resultProp)
}
// AppendResultIRIs appends the given IRIs to the Result property of 'with'.
func AppendResultIRIs(with WithResult, result ...*url.URL) {
appendIRIs(func() Property[vocab.ActivityStreamsResultPropertyIterator] {
resultProp := with.GetActivityStreamsResult()
if resultProp == nil {
resultProp = streams.NewActivityStreamsResultProperty()
with.SetActivityStreamsResult(resultProp)
}
return resultProp
}, result...)
}
// GetTargetIRIs returns the IRIs contained in the Target property of 'with'.
func GetTargetIRIs(with WithTarget) []*url.URL {
targetProp := with.GetActivityStreamsTarget()
@ -239,6 +292,42 @@ func AppendAttributedTo(with WithAttributedTo, attribTo ...*url.URL) {
}, attribTo...)
}
// GetInteractingObject returns IRIs contained in the interactingObject property of 'with'.
func GetInteractingObject(with WithInteractingObject) []*url.URL {
intObjProp := with.GetGoToSocialInteractingObject()
return getIRIs(intObjProp)
}
// AppendInteractingObject appends the given IRIs to the interactingObject property of 'with'.
func AppendInteractingObject(with WithInteractingObject, interactingObject ...*url.URL) {
appendIRIs(func() Property[vocab.GoToSocialInteractingObjectPropertyIterator] {
intObjProp := with.GetGoToSocialInteractingObject()
if intObjProp == nil {
intObjProp = streams.NewGoToSocialInteractingObjectProperty()
with.SetGoToSocialInteractingObject(intObjProp)
}
return intObjProp
}, interactingObject...)
}
// GetInteractionTarget returns IRIs contained in the interactionTarget property of 'with'.
func GetInteractionTarget(with WithInteractionTarget) []*url.URL {
intTargetProp := with.GetGoToSocialInteractionTarget()
return getIRIs(intTargetProp)
}
// AppendInteractionTarget appends the given IRIs to the interactionTarget property of 'with'.
func AppendInteractionTarget(with WithInteractionTarget, interactionTarget ...*url.URL) {
appendIRIs(func() Property[vocab.GoToSocialInteractionTargetPropertyIterator] {
intTargetProp := with.GetGoToSocialInteractionTarget()
if intTargetProp == nil {
intTargetProp = streams.NewGoToSocialInteractionTargetProperty()
with.SetGoToSocialInteractionTarget(intTargetProp)
}
return intTargetProp
}, interactionTarget...)
}
// GetInReplyTo returns the IRIs contained in the InReplyTo property of 'with'.
func GetInReplyTo(with WithInReplyTo) []*url.URL {
replyProp := with.GetActivityStreamsInReplyTo()
@ -539,14 +628,56 @@ func SetManuallyApprovesFollowers(with WithManuallyApprovesFollowers, manuallyAp
mafProp.Set(manuallyApprovesFollowers)
}
// GetHidesToPublicFromUnauthedWeb returns the boolean contained in the hidesToPublicFromUnauthedWeb property of 'with'.
//
// Returns default 'false' if property unusable or not set.
func GetHidesToPublicFromUnauthedWeb(with WithHidesToPublicFromUnauthedWeb) bool {
hidesProp := with.GetGoToSocialHidesToPublicFromUnauthedWeb()
if hidesProp == nil || !hidesProp.IsXMLSchemaBoolean() {
return false
}
return hidesProp.Get()
}
// SetHidesToPublicFromUnauthedWeb sets the given boolean on the hidesToPublicFromUnauthedWeb property of 'with'.
func SetHidesToPublicFromUnauthedWeb(with WithHidesToPublicFromUnauthedWeb, hidesToPublicFromUnauthedWeb bool) {
hidesProp := with.GetGoToSocialHidesToPublicFromUnauthedWeb()
if hidesProp == nil {
hidesProp = streams.NewGoToSocialHidesToPublicFromUnauthedWebProperty()
with.SetGoToSocialHidesToPublicFromUnauthedWeb(hidesProp)
}
hidesProp.Set(hidesToPublicFromUnauthedWeb)
}
// GetHidesCcPublicFromUnauthedWeb returns the boolean contained in the hidesCcPublicFromUnauthedWeb property of 'with'.
//
// Returns default 'true' if property unusable or not set.
func GetHidesCcPublicFromUnauthedWeb(with WithHidesCcPublicFromUnauthedWeb) bool {
hidesProp := with.GetGoToSocialHidesCcPublicFromUnauthedWeb()
if hidesProp == nil || !hidesProp.IsXMLSchemaBoolean() {
return true
}
return hidesProp.Get()
}
// SetHidesCcPublicFromUnauthedWeb sets the given boolean on the hidesCcPublicFromUnauthedWeb property of 'with'.
func SetHidesCcPublicFromUnauthedWeb(with WithHidesCcPublicFromUnauthedWeb, hidesCcPublicFromUnauthedWeb bool) {
hidesProp := with.GetGoToSocialHidesCcPublicFromUnauthedWeb()
if hidesProp == nil {
hidesProp = streams.NewGoToSocialHidesCcPublicFromUnauthedWebProperty()
with.SetGoToSocialHidesCcPublicFromUnauthedWeb(hidesProp)
}
hidesProp.Set(hidesCcPublicFromUnauthedWeb)
}
// GetApprovedBy returns the URL contained in
// the ApprovedBy property of 'with', if set.
func GetApprovedBy(with WithApprovedBy) *url.URL {
mafProp := with.GetGoToSocialApprovedBy()
if mafProp == nil || !mafProp.IsIRI() {
abProp := with.GetGoToSocialApprovedBy()
if abProp == nil || !abProp.IsIRI() {
return nil
}
return mafProp.Get()
return abProp.Get()
}
// SetApprovedBy sets the given url
@ -560,6 +691,177 @@ func SetApprovedBy(with WithApprovedBy, approvedBy *url.URL) {
abProp.Set(approvedBy)
}
// GetLikeAuthorization returns the URL contained in
// the likeAuthorization property of 'with', if set.
func GetLikeAuthorization(with WithLikeAuthorization) *url.URL {
laProp := with.GetGoToSocialLikeAuthorization()
if laProp == nil || !laProp.IsIRI() {
return nil
}
return laProp.Get()
}
// SetLikeAuthorization sets the given url on
// the 'likeAuthorization' property of 'with'.
func SetLikeAuthorization(with WithLikeAuthorization, likeAuthorization *url.URL) {
laProp := with.GetGoToSocialLikeAuthorization()
if laProp == nil {
laProp = streams.NewGoToSocialLikeAuthorizationProperty()
with.SetGoToSocialLikeAuthorization(laProp)
}
laProp.Set(likeAuthorization)
}
// GetReplyAuthorization returns the URL contained in
// the replyAuthorization property of 'with', if set.
func GetReplyAuthorization(with WithReplyAuthorization) *url.URL {
raProp := with.GetGoToSocialReplyAuthorization()
if raProp == nil || !raProp.IsIRI() {
return nil
}
return raProp.Get()
}
// SetReplyAuthorization sets the given url on
// the 'replyAuthorization' property of 'with'.
func SetReplyAuthorization(with WithReplyAuthorization, replyAuthorization *url.URL) {
raProp := with.GetGoToSocialReplyAuthorization()
if raProp == nil {
raProp = streams.NewGoToSocialReplyAuthorizationProperty()
with.SetGoToSocialReplyAuthorization(raProp)
}
raProp.Set(replyAuthorization)
}
// GetAnnounceAuthorization returns the URL contained in
// the announceAuthorization property of 'with', if set.
func GetAnnounceAuthorization(with WithAnnounceAuthorization) *url.URL {
aaProp := with.GetGoToSocialAnnounceAuthorization()
if aaProp == nil || !aaProp.IsIRI() {
return nil
}
return aaProp.Get()
}
// SetAnnounceAuthorization sets the given url on
// the 'announceAuthorization' property of 'with'.
func SetAnnounceAuthorization(with WithAnnounceAuthorization, announceAuthorization *url.URL) {
aaProp := with.GetGoToSocialAnnounceAuthorization()
if aaProp == nil {
aaProp = streams.NewGoToSocialAnnounceAuthorizationProperty()
with.SetGoToSocialAnnounceAuthorization(aaProp)
}
aaProp.Set(announceAuthorization)
}
// GetMediaType returns the string contained in
// the MediaType property of 'with', if set.
func GetMediaType(with WithMediaType) string {
mtProp := with.GetActivityStreamsMediaType()
if mtProp == nil || !mtProp.IsRFCRfc2045() {
return ""
}
return mtProp.Get()
}
// SetMediaType sets the given string
// on the MediaType property of 'with'.
func SetMediaType(with WithMediaType, mediaType string) {
mtProp := with.GetActivityStreamsMediaType()
if mtProp == nil {
mtProp = streams.NewActivityStreamsMediaTypeProperty()
with.SetActivityStreamsMediaType(mtProp)
}
mtProp.Set(mediaType)
}
// AppendName appends the given name
// vals to the Name property of 'with'.
func AppendName(with WithName, name ...string) {
if len(name) == 0 {
return
}
nameProp := with.GetActivityStreamsName()
if nameProp == nil {
nameProp = streams.NewActivityStreamsNameProperty()
with.SetActivityStreamsName(nameProp)
}
for _, name := range name {
nameProp.AppendXMLSchemaString(name)
}
}
// AppendSummary appends the given summary
// vals to the Summary property of 'with'.
func AppendSummary(with WithSummary, summary ...string) {
if len(summary) == 0 {
return
}
summaryProp := with.GetActivityStreamsSummary()
if summaryProp == nil {
summaryProp = streams.NewActivityStreamsSummaryProperty()
with.SetActivityStreamsSummary(summaryProp)
}
for _, summary := range summary {
summaryProp.AppendXMLSchemaString(summary)
}
}
// SetBlurhash sets the given string
// on the Blurhash property of 'with'.
func SetBlurhash(with WithBlurhash, mediaType string) {
bProp := with.GetTootBlurhash()
if bProp == nil {
bProp = streams.NewTootBlurhashProperty()
with.SetTootBlurhash(bProp)
}
bProp.Set(mediaType)
}
// AppendSensitive appends the given sensitive
// boolean to the `sensitive` property of 'with'.
func AppendSensitive(with WithSensitive, sensitive bool) {
sProp := with.GetActivityStreamsSensitive()
if sProp == nil {
sProp = streams.NewActivityStreamsSensitiveProperty()
with.SetActivityStreamsSensitive(sProp)
}
sProp.AppendXMLSchemaBoolean(sensitive)
}
// AppendContent appends the given content
// string to the `content` property of 'with'.
func AppendContent(with WithContent, content string) {
cProp := with.GetActivityStreamsContent()
if cProp == nil {
cProp = streams.NewActivityStreamsContentProperty()
with.SetActivityStreamsContent(cProp)
}
cProp.AppendXMLSchemaString(content)
}
// AppendContentMap appends the given content
// language map to the `content` property of 'with'.
func AppendContentMap(with WithContent, contentMap map[string]string) {
cProp := with.GetActivityStreamsContent()
if cProp == nil {
cProp = streams.NewActivityStreamsContentProperty()
with.SetActivityStreamsContent(cProp)
}
cProp.AppendRDFLangString(contentMap)
}
// SetReplies sets the given replies collection
// to the `replies` property of 'with'.
func SetReplies(with WithReplies, replies vocab.ActivityStreamsCollection) {
rProp := with.GetActivityStreamsReplies()
if rProp == nil {
rProp = streams.NewActivityStreamsRepliesProperty()
with.SetActivityStreamsReplies(rProp)
}
rProp.SetActivityStreamsCollection(replies)
}
// extractIRIs extracts just the AP IRIs from an iterable
// property that may contain types (with IRIs) or just IRIs.
//

View file

@ -0,0 +1,283 @@
// GoToSocial
// Copyright (C) GoToSocial Authors admin@gotosocial.org
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package ap_test
import (
"bytes"
"io"
"net/url"
"testing"
"code.superseriousbusiness.org/gotosocial/internal/ap"
"code.superseriousbusiness.org/gotosocial/testrig"
"github.com/stretchr/testify/suite"
)
type PropertiesTestSuite struct {
suite.Suite
}
func (suite *PropertiesTestSuite) TestGetStatusableURL() {
// Pretty good representation of
// how a peertube video is federated.
const peertubeVideo = `{
"@context": [
"https://www.w3.org/ns/activitystreams"
],
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [
"https://example.org/accounts/someone/followers"
],
"type": "Video",
"id": "https://example.org/videos/watch/942d51e6-9320-4f40-980b-76bba0652bc2",
"url": [
{
"type": "Link",
"mediaType": "text/html",
"href": "https://example.org/w/jifTXYpdLJSU269svW8Jdb"
},
{
"type": "Link",
"mediaType": "text/html",
"href": "https://example.org/videos/watch/942d51e6-9320-4f40-980b-76bba0652bc2"
},
{
"type": "Link",
"mediaType": "application/x-mpegURL",
"href": "https://example.org/static/streaming-playlists/hls/942d51e6-9320-4f40-980b-76bba0652bc2/3d412b0f-3f2e-4509-9d0f-0142223b1752-master.m3u8",
"tag": [
{
"type": "Infohash",
"name": "4b5a702f76333963655575616e627a5261426269"
},
{
"type": "Infohash",
"name": "4f6c5552324a39324a55447036735649586b4875"
},
{
"type": "Infohash",
"name": "476d4154793667574d6d594c7276523471364732"
},
{
"type": "Link",
"name": "sha256",
"mediaType": "application/json",
"href": "https://example.org/static/streaming-playlists/hls/942d51e6-9320-4f40-980b-76bba0652bc2/0c607a4c-ab78-4bed-aeef-9970abd88e77-segments-sha256.json"
},
{
"type": "Link",
"mediaType": "video/mp4",
"href": "https://example.org/static/streaming-playlists/hls/942d51e6-9320-4f40-980b-76bba0652bc2/c6b6c9fb-83da-425c-9ce6-680e00eb9ecb-480-fragmented.mp4",
"height": 480,
"width": 854,
"size": 11260985,
"fps": 30,
"attachment": [
{
"type": "PropertyValue",
"name": "ffprobe_codec_type",
"value": "video"
},
{
"type": "PropertyValue",
"name": "peertube_format_flag",
"value": "fragmented"
}
]
},
{
"type": "Link",
"rel": [
"metadata",
"video/mp4"
],
"mediaType": "application/json",
"href": "https://example.org/api/v1/videos/942d51e6-9320-4f40-980b-76bba0652bc2/metadata/236424",
"height": 480,
"width": 854,
"fps": 30
},
{
"type": "Link",
"mediaType": "application/x-bittorrent",
"href": "https://example.org/lazy-static/torrents/fac3fb9c-55a6-4e56-82f5-8de8a3f62d8f-480-hls.torrent",
"height": 480,
"width": 854,
"fps": 30
},
{
"type": "Link",
"mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
"href": "magnet:?xs=https%3A%2F%2Fexample.org%2Flazy-static%2Ftorrents%2Ffac3fb9c-55a6-4e56-82f5-8de8a3f62d8f-480-hls.torrent&xt=urn:btih:b5a55918c3a05c2459156b6f34570ea64c69fd5a&dn=Na+proch%C3%A1zce+%E2%99%A5%EF%B8%8F+Walking+with+our+gang+%F0%9F%98%83&tr=https%3A%2F%2Fexample.org%2Ftracker%2Fannounce&tr=wss%3A%2F%2Fexample.org%3A443%2Ftracker%2Fsocket&ws=https%3A%2F%2Fexample.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F942d51e6-9320-4f40-980b-76bba0652bc2%2Fc6b6c9fb-83da-425c-9ce6-680e00eb9ecb-480-fragmented.mp4",
"height": 480,
"width": 854,
"fps": 30
},
{
"type": "Link",
"mediaType": "video/mp4",
"href": "https://example.org/static/streaming-playlists/hls/942d51e6-9320-4f40-980b-76bba0652bc2/113ebf59-8e27-42f5-b971-d315f3fec77d-0-fragmented.mp4",
"height": 0,
"width": 0,
"size": 1472647,
"fps": 0,
"attachment": [
{
"type": "PropertyValue",
"name": "ffprobe_codec_type",
"value": "audio"
},
{
"type": "PropertyValue",
"name": "peertube_format_flag",
"value": "fragmented"
}
]
},
{
"type": "Link",
"rel": [
"metadata",
"video/mp4"
],
"mediaType": "application/json",
"href": "https://example.org/api/v1/videos/942d51e6-9320-4f40-980b-76bba0652bc2/metadata/236425",
"height": 0,
"width": 0,
"fps": 0
},
{
"type": "Link",
"mediaType": "application/x-bittorrent",
"href": "https://example.org/lazy-static/torrents/babc50e0-4643-4467-bde0-5d837d71fed5-0-hls.torrent",
"height": 0,
"width": 0,
"fps": 0
},
{
"type": "Link",
"mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
"href": "magnet:?xs=https%3A%2F%2Fexample.org%2Flazy-static%2Ftorrents%2Fbabc50e0-4643-4467-bde0-5d837d71fed5-0-hls.torrent&xt=urn:btih:395086b81fae8b1b9f7d0a03375c66214acff459&dn=Na+proch%C3%A1zce+%E2%99%A5%EF%B8%8F+Walking+with+our+gang+%F0%9F%98%83&tr=https%3A%2F%2Fexample.org%2Ftracker%2Fannounce&tr=wss%3A%2F%2Fexample.org%3A443%2Ftracker%2Fsocket&ws=https%3A%2F%2Fexample.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F942d51e6-9320-4f40-980b-76bba0652bc2%2F113ebf59-8e27-42f5-b971-d315f3fec77d-0-fragmented.mp4",
"height": 0,
"width": 0,
"fps": 0
}
]
},
{
"type": "Link",
"name": "tracker-http",
"rel": [
"tracker",
"http"
],
"href": "https://example.org/tracker/announce"
},
{
"type": "Link",
"name": "tracker-websocket",
"rel": [
"tracker",
"websocket"
],
"href": "wss://example.org:443/tracker/socket"
}
]
}`
// Mix of plain IRIs and Links,
// we should be able to parse this.
//
// The last one with no href should be ignored.
const mixedPlainURIsAndLinks = `{
"@context": [
"https://www.w3.org/ns/activitystreams"
],
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [
"https://example.org/accounts/someone/followers"
],
"type": "Video",
"id": "https://example.org/videos/watch/942d51e6-9320-4f40-980b-76bba0652bc2",
"url": [
"https://example.org/videos/watch/942d51e6-9320-4f40-980b-76bba0652bc2",
{
"type": "Link",
"mediaType": "text/html",
"href": "https://example.org/w/jifTXYpdLJSU269svW8Jdb"
},
{
"type": "Link",
"mediaType": "text/html",
"href": "https://example.org/videos/watch/942d51e6-9320-4f40-980b-76bba0652bc2"
},
{
"type": "Link",
"mediaType": "text/html"
}
]
}`
for i, test := range []struct {
in string
expectedURLs []*url.URL
}{
{
in: peertubeVideo,
expectedURLs: []*url.URL{
testrig.URLMustParse("https://example.org/w/jifTXYpdLJSU269svW8Jdb"),
testrig.URLMustParse("https://example.org/videos/watch/942d51e6-9320-4f40-980b-76bba0652bc2"),
testrig.URLMustParse("https://example.org/static/streaming-playlists/hls/942d51e6-9320-4f40-980b-76bba0652bc2/3d412b0f-3f2e-4509-9d0f-0142223b1752-master.m3u8"),
testrig.URLMustParse("https://example.org/tracker/announce"),
testrig.URLMustParse("wss://example.org:443/tracker/socket"),
},
},
{
in: mixedPlainURIsAndLinks,
expectedURLs: []*url.URL{
testrig.URLMustParse("https://example.org/videos/watch/942d51e6-9320-4f40-980b-76bba0652bc2"),
testrig.URLMustParse("https://example.org/w/jifTXYpdLJSU269svW8Jdb"),
testrig.URLMustParse("https://example.org/videos/watch/942d51e6-9320-4f40-980b-76bba0652bc2"),
},
},
} {
// Parse input to statusable.
statusable, err := ap.ResolveStatusable(
suite.T().Context(),
io.NopCloser(bytes.NewBufferString(test.in)),
)
if err != nil {
suite.FailNow(err.Error())
}
// Ensure URL fields as expected.
suite.EqualValues(
test.expectedURLs,
ap.GetURL(statusable),
"mismatch in test case %d", i,
)
}
}
func TestPropertiesTestSuite(t *testing.T) {
suite.Run(t, new(PropertiesTestSuite))
}

View file

@ -19,7 +19,6 @@ package ap_test
import (
"bytes"
"context"
"io"
"testing"
@ -36,7 +35,7 @@ func (suite *ResolveTestSuite) TestResolveDocumentAsStatusable() {
b := []byte(suite.typeToJson(suite.document1))
statusable, err := ap.ResolveStatusable(
context.Background(), io.NopCloser(bytes.NewReader(b)),
suite.T().Context(), io.NopCloser(bytes.NewReader(b)),
)
suite.NoError(err)
suite.NotNil(statusable)
@ -46,7 +45,7 @@ func (suite *ResolveTestSuite) TestResolveDocumentAsAccountable() {
b := []byte(suite.typeToJson(suite.document1))
accountable, err := ap.ResolveAccountable(
context.Background(), io.NopCloser(bytes.NewReader(b)),
suite.T().Context(), io.NopCloser(bytes.NewReader(b)),
)
suite.True(gtserror.IsWrongType(err))
suite.EqualError(err, "ResolveAccountable: cannot resolve vocab type *typedocument.ActivityStreamsDocument as accountable")
@ -58,7 +57,7 @@ func (suite *ResolveTestSuite) TestResolveHTMLAsAccountable() {
<title>.</title>`)
accountable, err := ap.ResolveAccountable(
context.Background(), io.NopCloser(bytes.NewReader(b)),
suite.T().Context(), io.NopCloser(bytes.NewReader(b)),
)
suite.True(gtserror.IsWrongType(err))
suite.EqualError(err, "ResolveAccountable: error decoding into json: invalid character '<' looking for beginning of value")
@ -73,7 +72,7 @@ func (suite *ResolveTestSuite) TestResolveNonAPJSONAsAccountable() {
}`)
accountable, err := ap.ResolveAccountable(
context.Background(), io.NopCloser(bytes.NewReader(b)),
suite.T().Context(), io.NopCloser(bytes.NewReader(b)),
)
suite.True(gtserror.IsWrongType(err))
suite.EqualError(err, "ResolveAccountable: error resolving json into ap vocab type: activity stream did not match any known types")
@ -124,7 +123,7 @@ func (suite *ResolveTestSuite) TestResolveBandwagonAlbumAsStatusable() {
}`)
statusable, err := ap.ResolveStatusable(
context.Background(), io.NopCloser(bytes.NewReader(b)),
suite.T().Context(), io.NopCloser(bytes.NewReader(b)),
)
suite.NoError(err)
suite.NotNil(statusable)

View file

@ -153,8 +153,8 @@ func serializeStatusable(t vocab.Type, includeContext bool) (map[string]interfac
NormalizeOutgoingAttachmentProp(statusable, data)
NormalizeOutgoingContentProp(statusable, data)
if ipa, ok := statusable.(InteractionPolicyAware); ok {
NormalizeOutgoingInteractionPolicyProp(ipa, data)
if wip, ok := statusable.(WithInteractionPolicy); ok {
NormalizeOutgoingInteractionPolicyProp(wip, data)
}
return data, nil

View file

@ -28,7 +28,6 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/db"
"code.superseriousbusiness.org/gotosocial/internal/email"
"code.superseriousbusiness.org/gotosocial/internal/federation"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/media"
"code.superseriousbusiness.org/gotosocial/internal/middleware"
@ -79,12 +78,6 @@ func (suite *EmojiGetTestSuite) SetupTest() {
suite.state.Storage = suite.storage
suite.tc = typeutils.NewConverter(&suite.state)
testrig.StartTimelines(
&suite.state,
visibility.NewFilter(&suite.state),
suite.tc,
)
suite.mediaManager = testrig.NewTestMediaManager(&suite.state)
suite.federator = testrig.NewTestFederator(&suite.state, testrig.NewTestTransportController(&suite.state, testrig.NewMockHTTPClient(nil, "../../../../testrig/media")), suite.mediaManager)
suite.emailSender = testrig.NewEmailSender("../../../../web/template/", nil)

View file

@ -0,0 +1,56 @@
// GoToSocial
// Copyright (C) GoToSocial Authors admin@gotosocial.org
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package users
import (
"net/http"
apiutil "code.superseriousbusiness.org/gotosocial/internal/api/util"
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
"github.com/gin-gonic/gin"
)
// AuthorizationGETHandler serves an accepted interaction request as a
// LikeAuthorization, ReplyAuthorization, or AnnounceAuthorization type.
func (m *Module) AuthorizationGETHandler(c *gin.Context) {
username, errWithCode := apiutil.ParseUsername(c.Param(apiutil.UsernameKey))
if errWithCode != nil {
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
reqID, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
if errWithCode != nil {
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
contentType, err := apiutil.NegotiateAccept(c, apiutil.ActivityPubHeaders...)
if err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
return
}
resp, errWithCode := m.processor.Fedi().AuthorizationGet(c.Request.Context(), username, reqID)
if errWithCode != nil {
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
return
}
apiutil.JSONType(c, http.StatusOK, contentType, resp)
}

View file

@ -19,7 +19,6 @@ package users_test
import (
"bytes"
"context"
"encoding/json"
"errors"
"io"
@ -193,7 +192,7 @@ func (suite *InboxPostTestSuite) newDelete(actorIRI string, objectIRI string, de
// Set the To of the delete as public
deleteTo := streams.NewActivityStreamsToProperty()
deleteTo.AppendIRI(ap.PublicURI())
deleteTo.AppendIRI(ap.PublicIRI())
delete.SetActivityStreamsTo(deleteTo)
// set some random-ass ID for the activity
@ -232,7 +231,7 @@ func (suite *InboxPostTestSuite) TestPostBlock() {
)
if !testrig.WaitFor(func() bool {
dbBlock, err = suite.db.GetBlock(context.Background(), requestingAccount.ID, targetAccount.ID)
dbBlock, err = suite.db.GetBlock(suite.T().Context(), requestingAccount.ID, targetAccount.ID)
return err == nil && dbBlock != nil
}) {
suite.FailNow("timed out waiting for block to be created")
@ -243,7 +242,7 @@ func (suite *InboxPostTestSuite) TestPostBlock() {
// one of our instance users should be able to undo that block.
func (suite *InboxPostTestSuite) TestPostUnblock() {
var (
ctx = context.Background()
ctx = suite.T().Context()
requestingAccount = suite.testAccounts["remote_account_1"]
targetAccount = suite.testAccounts["local_account_1"]
blockID = "http://fossbros-anonymous.io/blocks/01H1462TPRTVG2RTQCTSQ7N6Q0"
@ -315,7 +314,7 @@ func (suite *InboxPostTestSuite) TestPostUpdate() {
requestingAccount.Emojis = []*gtsmodel.Emoji{testEmoji}
// Create an update from the account.
accountable, err := suite.tc.AccountToAS(context.Background(), requestingAccount)
accountable, err := suite.tc.AccountToAS(suite.T().Context(), requestingAccount)
if err != nil {
suite.FailNow(err.Error())
}
@ -344,7 +343,7 @@ func (suite *InboxPostTestSuite) TestPostUpdate() {
if !testrig.WaitFor(func() bool {
// displayName should be updated
dbUpdatedAccount, _ = suite.db.GetAccountByID(context.Background(), requestingAccount.ID)
dbUpdatedAccount, _ = suite.db.GetAccountByID(suite.T().Context(), requestingAccount.ID)
return dbUpdatedAccount.DisplayName == updatedDisplayName
}) {
suite.FailNow("timed out waiting for account update")
@ -399,7 +398,7 @@ func (suite *InboxPostTestSuite) TestPostUpdate() {
func (suite *InboxPostTestSuite) TestPostDelete() {
var (
ctx = context.Background()
ctx = suite.T().Context()
requestingAccount = suite.testAccounts["remote_account_1"]
targetAccount = suite.testAccounts["local_account_1"]
activityID = requestingAccount.URI + "/some-new-activity/01FG9C441MCTW3R2W117V2PQK3"
@ -517,7 +516,7 @@ func (suite *InboxPostTestSuite) TestPostFromBlockedAccount() {
)
// Create an update from the account.
accountable, err := suite.tc.AccountToAS(context.Background(), requestingAccount)
accountable, err := suite.tc.AccountToAS(suite.T().Context(), requestingAccount)
if err != nil {
suite.FailNow(err.Error())
}
@ -559,7 +558,7 @@ func (suite *InboxPostTestSuite) TestPostFromBlockedAccountToOtherAccount() {
suite.signatureCheck,
)
_, err := suite.state.DB.GetStatusByURI(context.Background(), statusURI)
_, err := suite.state.DB.GetStatusByURI(suite.T().Context(), statusURI)
suite.ErrorIs(err, db.ErrNoEntries)
}

View file

@ -19,7 +19,6 @@ package users_test
import (
"bytes"
"context"
"encoding/json"
"io/ioutil"
"net/http"
@ -90,7 +89,7 @@ func (suite *OutboxGetTestSuite) TestGetOutbox() {
err = json.Unmarshal(b, &m)
suite.NoError(err)
t, err := streams.ToType(context.Background(), m)
t, err := streams.ToType(suite.T().Context(), m)
suite.NoError(err)
_, ok := t.(vocab.ActivityStreamsOrderedCollection)
@ -177,7 +176,7 @@ func (suite *OutboxGetTestSuite) TestGetOutboxFirstPage() {
err = json.Unmarshal(b, &m)
suite.NoError(err)
t, err := streams.ToType(context.Background(), m)
t, err := streams.ToType(suite.T().Context(), m)
suite.NoError(err)
_, ok := t.(vocab.ActivityStreamsOrderedCollectionPage)
@ -240,7 +239,7 @@ func (suite *OutboxGetTestSuite) TestGetOutboxNextPage() {
err = json.Unmarshal(b, &m)
suite.NoError(err)
t, err := streams.ToType(context.Background(), m)
t, err := streams.ToType(suite.T().Context(), m)
suite.NoError(err)
_, ok := t.(vocab.ActivityStreamsOrderedCollectionPage)

View file

@ -19,7 +19,6 @@ package users_test
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"
@ -101,7 +100,7 @@ func (suite *RepliesGetTestSuite) TestGetReplies() {
err = json.Unmarshal(b, &m)
assert.NoError(suite.T(), err)
t, err := streams.ToType(context.Background(), m)
t, err := streams.ToType(suite.T().Context(), m)
assert.NoError(suite.T(), err)
_, ok := t.(vocab.ActivityStreamsOrderedCollection)
@ -172,7 +171,7 @@ func (suite *RepliesGetTestSuite) TestGetRepliesNext() {
err = json.Unmarshal(b, &m)
assert.NoError(suite.T(), err)
t, err := streams.ToType(context.Background(), m)
t, err := streams.ToType(suite.T().Context(), m)
assert.NoError(suite.T(), err)
page, ok := t.(vocab.ActivityStreamsOrderedCollectionPage)
@ -243,7 +242,7 @@ func (suite *RepliesGetTestSuite) TestGetRepliesLast() {
err = json.Unmarshal(b, &m)
assert.NoError(suite.T(), err)
t, err := streams.ToType(context.Background(), m)
t, err := streams.ToType(suite.T().Context(), m)
assert.NoError(suite.T(), err)
page, ok := t.(vocab.ActivityStreamsOrderedCollectionPage)

Some files were not shown because too many files have changed in this diff Show more