Compare commits
110 commits
23fc70f4e6
...
1ee56d66ce
Author | SHA1 | Date | |
---|---|---|---|
|
1ee56d66ce | ||
|
dfcb7862a9 | ||
|
24f6760c0e | ||
|
fccb0bc102 | ||
|
37dbf319b1 | ||
|
d0de3ad492 | ||
|
2c95fd4115 | ||
|
4ac5447ad6 | ||
|
bb6d2f8ee8 | ||
|
576da4cf01 | ||
|
edcc8ea4ed | ||
|
787bdc1488 | ||
|
ce7ba8f498 | ||
|
128fcc871c | ||
|
05e89af4ec | ||
|
42bbbaadb2 | ||
|
a6d1f5bf2c | ||
|
62f25ea08a | ||
|
2aa3524739 | ||
|
e10de8464a | ||
|
00bd0f7658 | ||
|
1276cde4b3 | ||
|
1a8e42eeb3 | ||
|
dd094e4012 | ||
|
baed591a1d | ||
|
bfb81f5bac | ||
|
07d2770995 | ||
|
e1781ff52e | ||
|
a24048fc05 | ||
|
053d820845 | ||
|
acd3e80ae1 | ||
|
27844b7da2 | ||
|
8b74cad422 | ||
|
c086d4048c | ||
|
a6d852d1c5 | ||
|
77f25e21d7 | ||
|
f5eee56bb1 | ||
|
a55bd6d2bd | ||
|
c47b9bd1d1 | ||
|
fc895ade02 | ||
|
8a9422aa78 | ||
|
b9e0689359 | ||
|
ab758cc233 | ||
|
493de5c005 | ||
|
527587155a | ||
|
b3ecfe1e0a | ||
|
91cef3495d | ||
|
1ab960bf15 | ||
|
d16e4fa34d | ||
|
61141ac232 | ||
|
bfe8144fda | ||
|
65fb8abd42 | ||
|
9048290948 | ||
|
726d2ba483 | ||
|
3617e27afa | ||
|
7b7fc528f1 | ||
|
702d49207f | ||
|
a773768718 | ||
|
3428bc9633 | ||
|
5c96702cb5 | ||
|
2a46681147 | ||
|
3ab2d8621b | ||
|
4c052c85f5 | ||
|
71b50353eb | ||
|
3720251fca | ||
|
5b765d734e | ||
|
9333bbc4d0 | ||
|
b42cb7a802 | ||
|
1472d92a8d | ||
|
0a99901c65 | ||
|
5c0514e83c | ||
|
37fd7c7a6a | ||
|
9835d3e65d | ||
|
77ea30542b | ||
|
cfe6ac5a42 | ||
|
0096222c0e | ||
|
634d4f408f | ||
|
81b66ad7e3 | ||
|
b8ef9fc4bc | ||
|
e77c7e16b6 | ||
|
b95498b8c2 | ||
|
4d423102c1 | ||
|
8cfae010a9 | ||
|
8daa4dae34 | ||
|
451803b230 | ||
|
c013892ca2 | ||
|
e9bb7ddd3a | ||
|
77f1e79532 | ||
|
29da5b35a5 | ||
|
6b727404be | ||
|
0784aa3218 | ||
|
fe8d5f2307 | ||
|
1aa7f70660 | ||
|
9ae0c7b363 | ||
|
f78002f915 | ||
|
eb77ceeed6 | ||
|
c953f57e55 | ||
|
9697df0955 | ||
|
ec00dbd496 | ||
|
8504043024 | ||
|
fb12bbb10b | ||
|
60acdb21a9 | ||
|
fd3b1e64da | ||
|
acdd495c70 | ||
|
d9e722dea3 | ||
|
4fbe06e332 | ||
|
f72e753a21 | ||
|
a4e82cb7cc | ||
|
9477fd7eba | ||
|
642f5230e6 |
1954 changed files with 227676 additions and 324187 deletions
21
.drone.yml
21
.drone.yml
|
@ -94,7 +94,7 @@ steps:
|
|||
- pull_request
|
||||
|
||||
- name: snapshot
|
||||
image: superseriousbusiness/gotosocial-drone-build:0.7.0 # https://github.com/superseriousbusiness/gotosocial-drone-build
|
||||
image: superseriousbusiness/gotosocial-drone-build:0.8.0 # https://github.com/superseriousbusiness/gotosocial-drone-build
|
||||
volumes:
|
||||
- name: go-build-cache
|
||||
path: /root/.cache/go-build
|
||||
|
@ -117,18 +117,13 @@ steps:
|
|||
|
||||
# Login to Docker, push Docker image snapshots + manifests.
|
||||
- /go/dockerlogin.sh
|
||||
- docker push superseriousbusiness/gotosocial:snapshot-armv6
|
||||
- docker push superseriousbusiness/gotosocial:snapshot-armv7
|
||||
- docker push superseriousbusiness/gotosocial:snapshot-arm64v8
|
||||
- docker push superseriousbusiness/gotosocial:snapshot-amd64
|
||||
- docker manifest create superseriousbusiness/gotosocial:snapshot superseriousbusiness/gotosocial:snapshot-armv6 superseriousbusiness/gotosocial:snapshot-armv7 superseriousbusiness/gotosocial:snapshot-amd64 superseriousbusiness/gotosocial:snapshot-arm64v8
|
||||
- |
|
||||
docker manifest create superseriousbusiness/gotosocial:snapshot \
|
||||
superseriousbusiness/gotosocial:snapshot-amd64 \
|
||||
superseriousbusiness/gotosocial:snapshot-arm64v8
|
||||
- docker manifest push superseriousbusiness/gotosocial:snapshot
|
||||
- docker push superseriousbusiness/gotosocial:snapshot-armv6-moderncsqlite
|
||||
- docker push superseriousbusiness/gotosocial:snapshot-armv7-moderncsqlite
|
||||
- docker push superseriousbusiness/gotosocial:snapshot-arm64v8-moderncsqlite
|
||||
- docker push superseriousbusiness/gotosocial:snapshot-amd64-moderncsqlite
|
||||
- docker manifest create superseriousbusiness/gotosocial:snapshot-moderncsqlite superseriousbusiness/gotosocial:snapshot-armv6-moderncsqlite superseriousbusiness/gotosocial:snapshot-armv7-moderncsqlite superseriousbusiness/gotosocial:snapshot-amd64-moderncsqlite superseriousbusiness/gotosocial:snapshot-arm64v8-moderncsqlite
|
||||
- docker manifest push superseriousbusiness/gotosocial:snapshot-moderncsqlite
|
||||
|
||||
# Publish binary .tar.gz snapshots to S3.
|
||||
- /go/snapshot_publish.sh
|
||||
|
@ -141,7 +136,7 @@ steps:
|
|||
- main
|
||||
|
||||
- name: release
|
||||
image: superseriousbusiness/gotosocial-drone-build:0.7.0 # https://github.com/superseriousbusiness/gotosocial-drone-build
|
||||
image: superseriousbusiness/gotosocial-drone-build:0.8.0 # https://github.com/superseriousbusiness/gotosocial-drone-build
|
||||
volumes:
|
||||
- name: go-build-cache
|
||||
path: /root/.cache/go-build
|
||||
|
@ -210,7 +205,7 @@ clone:
|
|||
|
||||
steps:
|
||||
- name: mirror
|
||||
image: superseriousbusiness/gotosocial-drone-build:0.7.0
|
||||
image: superseriousbusiness/gotosocial-drone-build:0.8.0
|
||||
environment:
|
||||
ORIGIN_REPO: https://github.com/superseriousbusiness/gotosocial
|
||||
TARGET_REPO: https://codeberg.org/superseriousbusiness/gotosocial
|
||||
|
@ -223,6 +218,6 @@ steps:
|
|||
|
||||
---
|
||||
kind: signature
|
||||
hmac: c79f1c3b16db8da7e3b01b960021a583ec81069aff8afd4425f049dd140f0620
|
||||
hmac: 64ce0d466c7a48b6aa24a8836cfad7eae71faeae0b2e5342beb6428233a65eee
|
||||
|
||||
...
|
||||
|
|
258
.goreleaser.yml
258
.goreleaser.yml
|
@ -15,7 +15,7 @@ before:
|
|||
|
||||
# https://goreleaser.com/customization/build/
|
||||
builds:
|
||||
# DEFAULT WASM SQLITE BINARY BUILDS
|
||||
# DEFAULT WASM BINARY BUILDS
|
||||
-
|
||||
id: gotosocial
|
||||
main: ./cmd/gotosocial
|
||||
|
@ -39,27 +39,14 @@ builds:
|
|||
goos:
|
||||
- linux
|
||||
- freebsd
|
||||
- netbsd
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
- arm
|
||||
- arm64
|
||||
goarm:
|
||||
- 6
|
||||
- 7
|
||||
ignore:
|
||||
# Build FreeBSD
|
||||
# only for amd64.
|
||||
- goos: freebsd
|
||||
goarch: arm64
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
- goos: freebsd
|
||||
goarch: 386
|
||||
mod_timestamp: "{{ .CommitTimestamp }}"
|
||||
# MODERNC SQLITE BINARY BUILDS
|
||||
# NOWASM BINARY BUILDS
|
||||
-
|
||||
id: gotosocial_moderncsqlite
|
||||
id: gotosocial_nowasm
|
||||
main: ./cmd/gotosocial
|
||||
binary: gotosocial
|
||||
ldflags:
|
||||
|
@ -74,12 +61,15 @@ builds:
|
|||
- static_build
|
||||
- kvformat
|
||||
- timetzdata
|
||||
- nowasm
|
||||
- >-
|
||||
{{ if and (index .Env "DEBUG") (.Env.DEBUG) }}debugenv{{ end }}
|
||||
- moderncsqlite3
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
# moderncsqlite doesn't
|
||||
# build for netbsd right
|
||||
# now so leave it out.
|
||||
- linux
|
||||
- freebsd
|
||||
goarch:
|
||||
|
@ -91,8 +81,8 @@ builds:
|
|||
- 6
|
||||
- 7
|
||||
ignore:
|
||||
# Build FreeBSD
|
||||
# only for amd64.
|
||||
# Don't build BSDs
|
||||
# for arm/32-bit.
|
||||
- goos: freebsd
|
||||
goarch: arm64
|
||||
- goos: freebsd
|
||||
|
@ -103,7 +93,7 @@ builds:
|
|||
|
||||
# https://goreleaser.com/customization/docker/
|
||||
dockers:
|
||||
# DEFAULT WASM SQLITE DOCKER BUILDS
|
||||
# DEFAULT WASM DOCKER BUILDS
|
||||
-
|
||||
use: buildx
|
||||
goos: linux
|
||||
|
@ -150,194 +140,25 @@ dockers:
|
|||
- go.sum
|
||||
- cmd
|
||||
- internal
|
||||
-
|
||||
use: buildx
|
||||
goos: linux
|
||||
goarch: arm
|
||||
goarm: 6
|
||||
id: armv6
|
||||
ids:
|
||||
- gotosocial
|
||||
image_templates:
|
||||
- "superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-armv6"
|
||||
- "superseriousbusiness/{{ .ProjectName }}:latest-armv6"
|
||||
- "{{ if .IsSnapshot }}superseriousbusiness/{{ .ProjectName }}:snapshot-armv6{{ end }}"
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm/v6"
|
||||
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||
- "--label=org.opencontainers.image.title={{.ProjectName}}"
|
||||
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
|
||||
- "--label=org.opencontainers.image.version={{.Version}}"
|
||||
extra_files:
|
||||
- web
|
||||
- go.mod
|
||||
- go.sum
|
||||
- cmd
|
||||
- internal
|
||||
-
|
||||
use: buildx
|
||||
goos: linux
|
||||
goarch: arm
|
||||
goarm: 7
|
||||
id: armv7
|
||||
ids:
|
||||
- gotosocial
|
||||
image_templates:
|
||||
- "superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-armv7"
|
||||
- "superseriousbusiness/{{ .ProjectName }}:latest-armv7"
|
||||
- "{{ if .IsSnapshot }}superseriousbusiness/{{ .ProjectName }}:snapshot-armv7{{ end }}"
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm/v7"
|
||||
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||
- "--label=org.opencontainers.image.title={{.ProjectName}}"
|
||||
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
|
||||
- "--label=org.opencontainers.image.version={{.Version}}"
|
||||
extra_files:
|
||||
- web
|
||||
- go.mod
|
||||
- go.sum
|
||||
- cmd
|
||||
- internal
|
||||
# MODERNC SQLITE DOCKER BUILDS
|
||||
-
|
||||
use: buildx
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
id: amd64-moderncsqlite
|
||||
ids:
|
||||
- gotosocial_moderncsqlite
|
||||
image_templates:
|
||||
- "superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-amd64-moderncsqlite"
|
||||
- "superseriousbusiness/{{ .ProjectName }}:latest-amd64-moderncsqlite"
|
||||
- "{{ if .IsSnapshot }}superseriousbusiness/{{ .ProjectName }}:snapshot-amd64-moderncsqlite{{ end }}"
|
||||
build_flag_templates:
|
||||
- "--platform=linux/amd64"
|
||||
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||
- "--label=org.opencontainers.image.title={{.ProjectName}}"
|
||||
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
|
||||
- "--label=org.opencontainers.image.version={{.Version}}"
|
||||
extra_files:
|
||||
- web
|
||||
- go.mod
|
||||
- go.sum
|
||||
- cmd
|
||||
- internal
|
||||
-
|
||||
use: buildx
|
||||
goos: linux
|
||||
goarch: arm64
|
||||
id: arm64v8-moderncsqlite
|
||||
ids:
|
||||
- gotosocial_moderncsqlite
|
||||
image_templates:
|
||||
- "superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-arm64v8-moderncsqlite"
|
||||
- "superseriousbusiness/{{ .ProjectName }}:latest-arm64v8-moderncsqlite"
|
||||
- "{{ if .IsSnapshot }}superseriousbusiness/{{ .ProjectName }}:snapshot-arm64v8-moderncsqlite{{ end }}"
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm64/v8"
|
||||
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||
- "--label=org.opencontainers.image.title={{.ProjectName}}"
|
||||
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
|
||||
- "--label=org.opencontainers.image.version={{.Version}}"
|
||||
extra_files:
|
||||
- web
|
||||
- go.mod
|
||||
- go.sum
|
||||
- cmd
|
||||
- internal
|
||||
-
|
||||
use: buildx
|
||||
goos: linux
|
||||
goarch: arm
|
||||
goarm: 6
|
||||
id: armv6-moderncsqlite
|
||||
ids:
|
||||
- gotosocial_moderncsqlite
|
||||
image_templates:
|
||||
- "superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-armv6-moderncsqlite"
|
||||
- "superseriousbusiness/{{ .ProjectName }}:latest-armv6-moderncsqlite"
|
||||
- "{{ if .IsSnapshot }}superseriousbusiness/{{ .ProjectName }}:snapshot-armv6-moderncsqlite{{ end }}"
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm/v6"
|
||||
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||
- "--label=org.opencontainers.image.title={{.ProjectName}}"
|
||||
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
|
||||
- "--label=org.opencontainers.image.version={{.Version}}"
|
||||
extra_files:
|
||||
- web
|
||||
- go.mod
|
||||
- go.sum
|
||||
- cmd
|
||||
- internal
|
||||
-
|
||||
use: buildx
|
||||
goos: linux
|
||||
goarch: arm
|
||||
goarm: 7
|
||||
id: armv7-moderncsqlite
|
||||
ids:
|
||||
- gotosocial_moderncsqlite
|
||||
image_templates:
|
||||
- "superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-armv7-moderncsqlite"
|
||||
- "superseriousbusiness/{{ .ProjectName }}:latest-armv7-moderncsqlite"
|
||||
- "{{ if .IsSnapshot }}superseriousbusiness/{{ .ProjectName }}:snapshot-armv7-moderncsqlite{{ end }}"
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm/v7"
|
||||
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||
- "--label=org.opencontainers.image.title={{.ProjectName}}"
|
||||
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
|
||||
- "--label=org.opencontainers.image.version={{.Version}}"
|
||||
extra_files:
|
||||
- web
|
||||
- go.mod
|
||||
- go.sum
|
||||
- cmd
|
||||
- internal
|
||||
|
||||
# https://goreleaser.com/customization/docker_manifest/
|
||||
docker_manifests:
|
||||
# DEFAULT WASM SQLITE BUILDS
|
||||
- name_template: superseriousbusiness/{{ .ProjectName }}:{{ .Version }}
|
||||
image_templates:
|
||||
- superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-amd64
|
||||
- superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-arm64v8
|
||||
- superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-armv6
|
||||
- superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-armv7
|
||||
- name_template: superseriousbusiness/{{ .ProjectName }}:latest
|
||||
image_templates:
|
||||
- superseriousbusiness/{{ .ProjectName }}:latest-amd64
|
||||
- superseriousbusiness/{{ .ProjectName }}:latest-arm64v8
|
||||
- superseriousbusiness/{{ .ProjectName }}:latest-armv6
|
||||
- superseriousbusiness/{{ .ProjectName }}:latest-armv7
|
||||
- name_template: "{{ if .IsSnapshot }}superseriousbusiness/{{ .ProjectName }}:snapshot{{ end }}"
|
||||
image_templates:
|
||||
- superseriousbusiness/{{ .ProjectName }}:snapshot-amd64
|
||||
- superseriousbusiness/{{ .ProjectName }}:snapshot-arm64v8
|
||||
- superseriousbusiness/{{ .ProjectName }}:snapshot-armv6
|
||||
- superseriousbusiness/{{ .ProjectName }}:snapshot-armv7
|
||||
# MODERNC SQLITE BUILDS
|
||||
- name_template: superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-moderncsqlite
|
||||
image_templates:
|
||||
- superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-amd64-moderncsqlite
|
||||
- superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-arm64v8-moderncsqlite
|
||||
- superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-armv6-moderncsqlite
|
||||
- superseriousbusiness/{{ .ProjectName }}:{{ .Version }}-armv7-moderncsqlite
|
||||
- name_template: superseriousbusiness/{{ .ProjectName }}:latest-moderncsqlite
|
||||
image_templates:
|
||||
- superseriousbusiness/{{ .ProjectName }}:latest-amd64-moderncsqlite
|
||||
- superseriousbusiness/{{ .ProjectName }}:latest-arm64v8-moderncsqlite
|
||||
- superseriousbusiness/{{ .ProjectName }}:latest-armv6-moderncsqlite
|
||||
- superseriousbusiness/{{ .ProjectName }}:latest-armv7-moderncsqlite
|
||||
- name_template: "{{ if .IsSnapshot }}superseriousbusiness/{{ .ProjectName }}:snapshot-moderncsqlite{{ end }}"
|
||||
image_templates:
|
||||
- superseriousbusiness/{{ .ProjectName }}:snapshot-amd64-moderncsqlite
|
||||
- superseriousbusiness/{{ .ProjectName }}:snapshot-arm64v8-moderncsqlite
|
||||
- superseriousbusiness/{{ .ProjectName }}:snapshot-armv6-moderncsqlite
|
||||
- superseriousbusiness/{{ .ProjectName }}:snapshot-armv7-moderncsqlite
|
||||
|
||||
# https://goreleaser.com/customization/archive/
|
||||
archives:
|
||||
# DEFAULT WASM SQLITE BUILD
|
||||
# DEFAULT WASM BUILD
|
||||
-
|
||||
id: gotosocial
|
||||
builds:
|
||||
|
@ -354,11 +175,11 @@ archives:
|
|||
- example/config.yaml
|
||||
- example/gotosocial.service
|
||||
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 \"v1\") }}{{ .Amd64 }}{{ end }}"
|
||||
# MODERNC SQLITE BUILD
|
||||
# NOWASM BUILD
|
||||
-
|
||||
id: gotosocial_moderncsqlite
|
||||
id: gotosocial_nowasm
|
||||
builds:
|
||||
- gotosocial_moderncsqlite
|
||||
- gotosocial_nowasm
|
||||
files:
|
||||
# standard release files
|
||||
- LICENSE
|
||||
|
@ -370,7 +191,7 @@ archives:
|
|||
# example config files
|
||||
- example/config.yaml
|
||||
- example/gotosocial.service
|
||||
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 \"v1\") }}{{ .Amd64 }}{{ end }}_moderncsqlite"
|
||||
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 \"v1\") }}{{ .Amd64 }}{{ end }}_nowasm"
|
||||
-
|
||||
id: web-assets
|
||||
files:
|
||||
|
@ -460,43 +281,26 @@ release:
|
|||
|
||||
### Which release archive/container should I use?
|
||||
|
||||
Tl;dr: Regardless of whether you're using SQLite or Postgres as your DB driver, you most likely you want the regular version without `moderncsqlite` in the name.
|
||||
GoToSocial releases binary builds for 64-bit Linux, FreeBSD, and NetBSD operating systems. We also release Docker builds for 64-bit Linux.
|
||||
|
||||
| OS | Architecture | Support level | Binary archive | Docker |
|
||||
| ------- | ----------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
|
||||
| Linux | x86-64/AMD64 (64-bit) | 🟢 Full | [linux_amd64.tar.gz](https://github.com/superseriousbusiness/gotosocial/releases/download/{{ .Tag }}/gotosocial_{{ .Version }}_linux_amd64.tar.gz) | `superseriousbusiness/gotosocial:{{ .Version }}` |
|
||||
| Linux | Armv8/ARM64 (64-bit) | 🟢 Full | [linux_arm64.tar.gz](https://github.com/superseriousbusiness/gotosocial/releases/download/{{ .Tag }}/gotosocial_{{ .Version }}_linux_arm64.tar.gz) | `superseriousbusiness/gotosocial:{{ .Version }}` |
|
||||
| FreeBSD | x86-64/AMD64 (64-bit) | 🟢 Full | [freebsd_amd64.tar.gz](https://github.com/superseriousbusiness/gotosocial/releases/download/{{ .Tag }}/gotosocial_{{ .Version }}_freebsd_amd64.tar.gz) | Not provided |
|
||||
| FreeBSD | Armv8/ARM64 (64-bit) | 🟢 Full | [freebsd_arm64.tar.gz](https://github.com/superseriousbusiness/gotosocial/releases/download/{{ .Tag }}/gotosocial_{{ .Version }}_freebsd_arm64.tar.gz) | Not provided |
|
||||
| NetBSD | x86-64/AMD64 (64-bit) | 🟢 Full | [netbsd_amd64.tar.gz](https://github.com/superseriousbusiness/gotosocial/releases/download/{{ .Tag }}/gotosocial_{{ .Version }}_netbsd_amd64.tar.gz) | Not provided |
|
||||
| NetBSD | Armv8/ARM64 (64-bit) | 🟢 Full | [netbsd_arm64.tar.gz](https://github.com/superseriousbusiness/gotosocial/releases/download/{{ .Tag }}/gotosocial_{{ .Version }}_netbsd_arm64.tar.gz) | Not provided |
|
||||
|
||||
However, if you're on FreeBSD, 32-bit Linux or 32-bit ARM, we recommend using the `moderncsqlite` version instead.
|
||||
#### `nowasm`
|
||||
|
||||
You may need to change some configuration options too. See the table below:
|
||||
For your convenience, we also provide **UNSUPPORTED, EXPERIMENTAL BUILDS**, created using the `nowasm` tag, in the downloads list below. There is no Docker build for `nowasm`.
|
||||
|
||||
| OS | Architecture | Support level | Binary archive | Docker |
|
||||
| ------- | ----------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
|
||||
| Linux | x86-64/AMD64 (64-bit) | 🟢 Full | [linux_amd64.tar.gz](https://github.com/superseriousbusiness/gotosocial/releases/download/{{ .Tag }}/gotosocial_{{ .Version }}_linux_amd64.tar.gz) | `superseriousbusiness/gotosocial:{{ .Version }}` |
|
||||
| Linux | Armv8/ARM64 (64-bit) | 🟢 Full | [linux_arm64.tar.gz](https://github.com/superseriousbusiness/gotosocial/releases/download/{{ .Tag }}/gotosocial_{{ .Version }}_linux_arm64.tar.gz) | `superseriousbusiness/gotosocial:{{ .Version }}` |
|
||||
| FreeBSD | x86-64/AMD64 (64-bit) | 🟢 Full<sup>[1](#freebsd)</sup> | [freebsd_amd64_moderncsqlite.tar.gz](https://github.com/superseriousbusiness/gotosocial/releases/download/{{ .Tag }}/gotosocial_{{ .Version }}_freebsd_amd64_moderncsqlite.tar.gz) | None provided |
|
||||
| Linux | x86-32/i386 (32-bit) | 🟡 Partial<sup>[2](#32-bit)</sup> | [linux_386_moderncsqlite.tar.gz](https://github.com/superseriousbusiness/gotosocial/releases/download/{{ .Tag }}/gotosocial_{{ .Version }}_linux_386_moderncsqlite.tar.gz) | `superseriousbusiness/gotosocial:{{ .Version }}-moderncsqlite` |
|
||||
| Linux | Armv7/ARM32 (32-bit) | 🟡 Partial<sup>[2](#32-bit)</sup> | [linux_armv7_moderncsqlite.tar.gz](https://github.com/superseriousbusiness/gotosocial/releases/download/{{ .Tag }}/gotosocial_{{ .Version }}_linux_armv7_moderncsqlite.tar.gz) | `superseriousbusiness/gotosocial:{{ .Version }}-moderncsqlite` |
|
||||
| Linux | Armv6/ARM32 (32-bit) | 🟡 Partial<sup>[2](#32-bit)</sup> | [linux_armv6_moderncsqlite.tar.gz](https://github.com/superseriousbusiness/gotosocial/releases/download/{{ .Tag }}/gotosocial_{{ .Version }}_linux_armv7_moderncsqlite.tar.gz) | `superseriousbusiness/gotosocial:{{ .Version }}-moderncsqlite` |
|
||||
GoToSocial releases built with `nowasm` use the Go-native, modernc version of SQLite instead of the WASM one, and will use *on-system ffmpeg and ffprobe binaries* for media processing.
|
||||
|
||||
#### FreeBSD
|
||||
Using a `nowasm` build is currently the only way to run GoToSocial on a 32-bit system.
|
||||
|
||||
`moderncsqlite` version currently recommended, though you might have success with the regular WASM SQLite version.
|
||||
|
||||
If running with regular WASM SQLite and having instability or memory issues, the following settings *may* help:
|
||||
|
||||
```yaml
|
||||
db-max-open-conns-multiplier: 0
|
||||
db-sqlite-journal-mode: "TRUNCATE"
|
||||
db-sqlite-synchronous: "FULL"
|
||||
```
|
||||
|
||||
#### 32-bit
|
||||
|
||||
`moderncsqlite` version is needed, as performance with regular WASM SQLite is not guaranteed when running on 32-bit.
|
||||
|
||||
Remote media processing will likely not work with reasonable performance, so you should set the following config variables to prevent download of remote media onto your instance:
|
||||
|
||||
```yaml
|
||||
media-remote-max-size: 0
|
||||
media-emoji-remote-max-size: 0
|
||||
```
|
||||
For more information on running a `nowasm` build, see the [nowasm](https://docs.gotosocial.org/en/latest/advanced/builds/nowasm/) documentation page.
|
||||
|
||||
# https://goreleaser.com/customization/changelog/
|
||||
changelog:
|
||||
|
|
|
@ -149,7 +149,7 @@ In case this post disappears, here are the steps (slightly modified):
|
|||
>
|
||||
> Add your fork as origin:
|
||||
>
|
||||
> `git remote add origin git@github.com/yourgithubname/gotosocial`
|
||||
> `git remote add origin git@github.com:yourgithubname/gotosocial`
|
||||
>
|
||||
|
||||
Be sure to run `git fetch` before building the project for the first time.
|
||||
|
@ -489,7 +489,7 @@ You can install go-swagger following the instructions [here](https://goswagger.i
|
|||
If you change Swagger annotations on any of the API paths, you can generate a new Swagger file at `./docs/api/swagger.yaml` by running:
|
||||
|
||||
```bash
|
||||
swagger generate spec --scan-models --exclude-deps -o docs/api/swagger.yaml
|
||||
go run github.com/go-swagger/go-swagger/cmd/swagger generate spec --scan-models --exclude-deps --output docs/api/swagger.yaml
|
||||
```
|
||||
|
||||
### CI/CD configuration
|
||||
|
|
50
README.md
50
README.md
|
@ -43,7 +43,8 @@ Here's a screenshot of the instance landing page! Check out the project's [offic
|
|||
- [Known Issues](#known-issues)
|
||||
- [Installing GoToSocial](#installing-gotosocial)
|
||||
- [Supported Platforms](#supported-platforms)
|
||||
- [FreeBSD](#freebsd)
|
||||
- [64-bit](#64-bit)
|
||||
- [BSDs](#bsds)
|
||||
- [32-bit](#32-bit)
|
||||
- [OpenBSD](#openbsd)
|
||||
- [Stable Releases](#stable-releases)
|
||||
|
@ -225,10 +226,11 @@ Simply download the binary + assets (or Docker container), tweak your configurat
|
|||
|
||||
### Safety + security features
|
||||
|
||||
- Built-in, automatic support for secure HTTPS with [Let's Encrypt](https://letsencrypt.org/).
|
||||
- Strict privacy enforcement for posts and strict blocking logic.
|
||||
- Import and export allow lists and deny lists. Subscribe to community-created block lists (think Ad blocker, but for federation!) (feature still in progress).
|
||||
- Strict privacy enforcement for posts, and strict blocking logic.
|
||||
- [Choose the visibility of posts on the web view of your profile](https://docs.gotosocial.org/en/latest/user_guide/settings/#visibility-level-of-posts-to-show-on-your-profile).
|
||||
- [Import, export](https://docs.gotosocial.org/en/latest/admin/settings/#importexport), and [subscribe](https://docs.gotosocial.org/en/latest/admin/domain_permission_subscriptions) to community-created domain allow and domain block lists.
|
||||
- HTTP signature authentication: GoToSocial requires [HTTP Signatures](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12) when sending and receiving messages, to ensure that your messages can't be tampered with and your identity can't be forged.
|
||||
- Built-in, automatic support for secure HTTPS with [Let's Encrypt](https://letsencrypt.org/).
|
||||
|
||||
### Various federation modes
|
||||
|
||||
|
@ -275,19 +277,32 @@ Platforms that we don't officially support *may* still work, but we can't test o
|
|||
|
||||
This is the current status of support offered by GoToSocial for different platforms (if something is unlisted it means we haven't checked yet so we don't know):
|
||||
|
||||
| OS | Architecture | Support level | Binary archive | Docker container |
|
||||
| ------- | ----------------------- | ---------------------------------- | -------------- | ---------------- |
|
||||
| Linux | x86-64/AMD64 (64-bit) | 🟢 Full | Yes | Yes |
|
||||
| Linux | Armv8/ARM64 (64-bit) | 🟢 Full | Yes | Yes |
|
||||
| FreeBSD | x86-64/AMD64 (64-bit) | 🟢 Full<sup>[1](#freebsd)</sup> | Yes | No |
|
||||
| Linux | x86-32/i386 (32-bit) | 🟡 Partial<sup>[2](#32-bit)</sup> | Yes | Yes |
|
||||
| Linux | Armv7/ARM32 (32-bit) | 🟡 Partial<sup>[2](#32-bit)</sup> | Yes | Yes |
|
||||
| Linux | Armv6/ARM32 (32-bit) | 🟡 Partial<sup>[2](#32-bit)</sup> | Yes | Yes |
|
||||
| OpenBSD | Any | 🔴 None<sup>[3](#openbsd)</sup> | No | No |
|
||||
| OS | Architecture | Support level | Binary archive | Docker container |
|
||||
| ------- | ----------------------- | ----------------------------------------- | -------------- | ---------------- |
|
||||
| Linux | x86-64/AMD64 (64-bit) | 🟢 Full<sup>[1](#64-bit)</sup> | Yes | Yes |
|
||||
| Linux | Armv8/ARM64 (64-bit) | 🟢 Full<sup>[1](#64-bit)</sup> | Yes | Yes |
|
||||
| FreeBSD | x86-64/AMD64 (64-bit) | 🟢 Full<sup>[1](#64-bit),[2](#bsds)</sup> | Yes | No |
|
||||
| FreeBSD | Armv8/ARM64 (64-bit) | 🟢 Full<sup>[1](#64-bit),[2](#bsds)</sup> | Yes | No |
|
||||
| NetBSD | x86-64/AMD64 (64-bit) | 🟢 Full<sup>[1](#64-bit),[2](#bsds)</sup> | Yes | No |
|
||||
| NetBSD | Armv8/ARM64 (64-bit) | 🟢 Full<sup>[1](#64-bit),[2](#bsds)</sup> | Yes | No |
|
||||
| Linux | x86-32/i386 (32-bit) | 🟡 Partial<sup>[3](#32-bit)</sup> | Yes | Yes |
|
||||
| Linux | Armv7/ARM32 (32-bit) | 🟡 Partial<sup>[3](#32-bit)</sup> | Yes | Yes |
|
||||
| Linux | Armv6/ARM32 (32-bit) | 🟡 Partial<sup>[3](#32-bit)</sup> | Yes | Yes |
|
||||
| OpenBSD | Any | 🔴 None<sup>[4](#openbsd)</sup> | No | No |
|
||||
|
||||
#### FreeBSD
|
||||
#### 64-bit
|
||||
|
||||
Mostly works, just a few issues with WASM SQLite; check release notes carefully when installing on FreeBSD. If running with Postgres you should have no issues.
|
||||
64-bit platforms require the following (now, very common) CPU features:
|
||||
|
||||
- x86-64 require SSE4.1 (for both media decoding and WASM SQLite)
|
||||
|
||||
- Armv8 require ARM64 Large System Extensions (specifically when using WASM SQLite)
|
||||
|
||||
Without these features, performance will suffer. In these situations, you may have some success building a binary yourself with the totally **unsupported, experimental** [nowasm](https://docs.gotosocial.org/en/latest/advanced/builds/nowasm/) tag.
|
||||
|
||||
#### BSDs
|
||||
|
||||
Mostly works, just [a few things to keep in mind](https://github.com/ncruces/go-sqlite3/wiki/Support-matrix) with WASM SQLite; check release notes carefully when installing on NetBSD or FreeBSD. If running with Postgres you should have no issues.
|
||||
|
||||
#### 32-bit
|
||||
|
||||
|
@ -295,11 +310,11 @@ GtS doesn't work well on 32-bit systems like i386, or Armv6/v7, mainly due to pe
|
|||
|
||||
We don't recommend running GtS on 32-bit, but you may have some success either turning off remote media processing altogether, or building a binary yourself with the totally **unsupported, experimental** [nowasm](https://docs.gotosocial.org/en/latest/advanced/builds/nowasm/) tag.
|
||||
|
||||
For more guidance, check release notes when trying to install on 32-bit.
|
||||
For more guidance, check release notes when trying to install on 32-bit.
|
||||
|
||||
#### OpenBSD
|
||||
|
||||
Marked as unsupported due to performance issues (high memory usage when idle, crashes while processing media).
|
||||
Marked as unsupported due to performance issues (no WASM compiler, high memory usage when idle, crashes while processing media).
|
||||
|
||||
While we don't support running GtS on OpenBSD, you may have some success building a binary yourself with the totally **unsupported, experimental** [nowasm](https://docs.gotosocial.org/en/latest/advanced/builds/nowasm/) tag.
|
||||
|
||||
|
@ -420,6 +435,7 @@ The following open source libraries, frameworks, and tools are used by GoToSocia
|
|||
- [superseriousbusiness/exif-terminator](https://codeberg.org/superseriousbusiness/exif-terminator); EXIF data removal. [GNU AGPL v3 LICENSE](https://spdx.org/licenses/AGPL-3.0-or-later.html).
|
||||
- [superseriousbusiness/httpsig](https://github.com/superseriousbusiness/httpsig) forked from [go-fed/httpsig](https://github.com/go-fed/httpsig); secure HTTP signature library. [BSD-3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html).
|
||||
- [superseriousbusiness/oauth2](https://github.com/superseriousbusiness/oauth2) forked from [go-oauth2/oauth2](https://github.com/go-oauth2/oauth2); OAuth server framework and token handling. [MIT License](https://spdx.org/licenses/MIT.html).
|
||||
- [temoto/robotstxt](https://github.com/temoto/robotstxt); robots.txt parsing. [MIT License](https://spdx.org/licenses/MIT.html).
|
||||
- [tdewolff/minify](https://github.com/tdewolff/minify); HTML minification for Markdown-submitted posts. [MIT License](https://spdx.org/licenses/MIT.html).
|
||||
- [uber-go/automaxprocs](https://github.com/uber-go/automaxprocs); GOMAXPROCS automation. [MIT License](https://spdx.org/licenses/MIT.html).
|
||||
- [ulule/limiter](https://github.com/ulule/limiter); http rate limit middleware. [MIT License](https://spdx.org/licenses/MIT.html).
|
||||
|
|
|
@ -71,7 +71,7 @@ These are provided in no specific order.
|
|||
- [x] **Filters v2** -- implement v2 of the filters API.
|
||||
- [x] **Mute accounts** -- mute accounts to prevent their posts showing up in your home timeline (optional: for limited period of time).
|
||||
- [x] **Non-replyable posts** -- design a non-replyable post path for GoToSocial based on https://github.com/mastodon/mastodon/issues/14762#issuecomment-1196889788; allow users to create non-replyable posts.
|
||||
- [ ] **Block + allow list subscriptions** -- allow instance admins to subscribe their instance to plaintext domain block/allow lists (much of the work for this is already in place).
|
||||
- [x] **Block + allow list subscriptions** -- allow instance admins to subscribe their instance to domain block/allow lists.
|
||||
- [x] **Direct conversation view** -- allow users to easily page through all direct-message conversations they're a part of.
|
||||
- [ ] **Oauth token management** -- create / view / invalidate OAuth tokens via the settings panel.
|
||||
- [ ] **Status EDIT support** -- edit statuses that you've created, without having to delete + redraft. Federate edits out properly.
|
||||
|
|
|
@ -40,7 +40,8 @@ func initState(ctx context.Context) (*state.State, error) {
|
|||
state.Caches.Init()
|
||||
state.Caches.Start()
|
||||
|
||||
// Set the state DB connection
|
||||
// Only set state DB connection.
|
||||
// Don't need Actions or Workers for this (yet).
|
||||
dbConn, err := bundb.NewBunDBService(ctx, &state)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating dbConn: %w", err)
|
||||
|
|
|
@ -127,6 +127,8 @@ func setupList(ctx context.Context) (*list, error) {
|
|||
state.Caches.Init()
|
||||
state.Caches.Start()
|
||||
|
||||
// Only set state DB connection.
|
||||
// Don't need Actions or Workers for this.
|
||||
dbService, err := bundb.NewBunDBService(ctx, &state)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating dbservice: %w", err)
|
||||
|
|
|
@ -45,10 +45,12 @@ func setupPrune(ctx context.Context) (*prune, error) {
|
|||
state.Caches.Start()
|
||||
|
||||
// Scheduler is required for the
|
||||
// claner, but no other workers
|
||||
// cleaner, but no other workers
|
||||
// are needed for this CLI action.
|
||||
state.Workers.StartScheduler()
|
||||
|
||||
// Set state DB connection.
|
||||
// Don't need Actions for this.
|
||||
dbService, err := bundb.NewBunDBService(ctx, &state)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating dbservice: %w", err)
|
||||
|
|
|
@ -33,12 +33,12 @@
|
|||
var Export action.GTSAction = func(ctx context.Context) error {
|
||||
var state state.State
|
||||
|
||||
// Only set state DB connection.
|
||||
// Don't need Actions or Workers for this.
|
||||
dbConn, err := bundb.NewBunDBService(ctx, &state)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating dbservice: %s", err)
|
||||
}
|
||||
|
||||
// Set the state DB connection
|
||||
state.DB = dbConn
|
||||
|
||||
exporter := trans.NewExporter(dbConn)
|
||||
|
|
|
@ -33,12 +33,12 @@
|
|||
var Import action.GTSAction = func(ctx context.Context) error {
|
||||
var state state.State
|
||||
|
||||
// Only set state DB connection.
|
||||
// Don't need Actions or Workers for this.
|
||||
dbConn, err := bundb.NewBunDBService(ctx, &state)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating dbservice: %s", err)
|
||||
}
|
||||
|
||||
// Set the state DB connection
|
||||
state.DB = dbConn
|
||||
|
||||
importer := trans.NewImporter(dbConn)
|
||||
|
|
|
@ -32,41 +32,72 @@
|
|||
"github.com/KimMachineGun/automemlimit/memlimit"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/admin"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/cleaner"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/filter/interaction"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/filter/spam"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/filter/visibility"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/media/ffmpeg"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/messages"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/metrics"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/middleware"
|
||||
tlprocessor "github.com/superseriousbusiness/gotosocial/internal/processing/timeline"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/timeline"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/tracing"
|
||||
"go.uber.org/automaxprocs/maxprocs"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db/bundb"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/email"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/federation"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/federation/federatingdb"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/filter/interaction"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/filter/spam"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/filter/visibility"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/httpclient"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/media"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/media/ffmpeg"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/messages"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/middleware"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/observability"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/oidc"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/processing"
|
||||
tlprocessor "github.com/superseriousbusiness/gotosocial/internal/processing/timeline"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/router"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/state"
|
||||
gtsstorage "github.com/superseriousbusiness/gotosocial/internal/storage"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/subscriptions"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/timeline"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/transport"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/typeutils"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/web"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/webpush"
|
||||
"go.uber.org/automaxprocs/maxprocs"
|
||||
)
|
||||
|
||||
// Maintenance starts and creates a GoToSocial server
|
||||
// in maintenance mode (returns 503 for most requests).
|
||||
var Maintenance action.GTSAction = func(ctx context.Context) error {
|
||||
route, err := router.New(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating maintenance router: %w", err)
|
||||
}
|
||||
|
||||
// Route maintenance handlers.
|
||||
maintenance := web.NewMaintenance()
|
||||
maintenance.Route(route)
|
||||
|
||||
// Start the maintenance router.
|
||||
if err := route.Start(); err != nil {
|
||||
return fmt.Errorf("error starting maintenance router: %w", err)
|
||||
}
|
||||
|
||||
// Catch shutdown signals from the OS.
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
sig := <-sigs // block until signal received
|
||||
log.Infof(ctx, "received signal %s, shutting down", sig)
|
||||
|
||||
if err := route.Stop(); err != nil {
|
||||
log.Errorf(ctx, "error stopping router: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start creates and starts a gotosocial server
|
||||
var Start action.GTSAction = func(ctx context.Context) error {
|
||||
// Set GOMAXPROCS / GOMEMLIMIT
|
||||
|
@ -146,8 +177,25 @@
|
|||
log.Info(ctx, "done! exiting...")
|
||||
}()
|
||||
|
||||
// Create maintenance router.
|
||||
var err error
|
||||
route, err = router.New(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating maintenance router: %w", err)
|
||||
}
|
||||
|
||||
// Route maintenance handlers.
|
||||
maintenance := web.NewMaintenance()
|
||||
maintenance.Route(route)
|
||||
|
||||
// Start the maintenance router to handle reqs
|
||||
// while the instance is starting up / migrating.
|
||||
if err := route.Start(); err != nil {
|
||||
return fmt.Errorf("error starting maintenance router: %w", err)
|
||||
}
|
||||
|
||||
// Initialize tracing (noop if not enabled).
|
||||
if err := tracing.Initialize(); err != nil {
|
||||
if err := observability.InitializeTracing(); err != nil {
|
||||
return fmt.Errorf("error initializing tracing: %w", err)
|
||||
}
|
||||
|
||||
|
@ -164,6 +212,10 @@
|
|||
// Set DB on state.
|
||||
state.DB = dbService
|
||||
|
||||
// Set Actions on state, providing workers to
|
||||
// Actions as well for triggering side effects.
|
||||
state.AdminActions = admin.New(dbService, &state.Workers)
|
||||
|
||||
// Ensure necessary database instance prerequisites exist.
|
||||
if err := dbService.CreateInstanceAccount(ctx); err != nil {
|
||||
return fmt.Errorf("error creating instance account: %s", err)
|
||||
|
@ -242,6 +294,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Get or create a VAPID key pair.
|
||||
if _, err := dbService.GetVAPIDKeyPair(ctx); err != nil {
|
||||
return gtserror.Newf("error getting or creating VAPID key pair: %w", err)
|
||||
}
|
||||
|
||||
// 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),
|
||||
|
@ -283,25 +343,39 @@ func(context.Context, time.Time) {
|
|||
// Create background cleaner.
|
||||
cleaner := cleaner.New(state)
|
||||
|
||||
// Now schedule background cleaning tasks.
|
||||
if err := cleaner.ScheduleJobs(); err != nil {
|
||||
return fmt.Errorf("error scheduling cleaner jobs: %w", err)
|
||||
}
|
||||
// Create subscriptions fetcher.
|
||||
subscriptions := subscriptions.New(
|
||||
state,
|
||||
transportController,
|
||||
typeConverter,
|
||||
)
|
||||
|
||||
// Create the processor using all the
|
||||
// other services we've created so far.
|
||||
process = processing.NewProcessor(
|
||||
cleaner,
|
||||
subscriptions,
|
||||
typeConverter,
|
||||
federator,
|
||||
oauthServer,
|
||||
mediaManager,
|
||||
state,
|
||||
emailSender,
|
||||
webPushSender,
|
||||
visFilter,
|
||||
intFilter,
|
||||
)
|
||||
|
||||
// Schedule background cleaning tasks.
|
||||
if err := cleaner.ScheduleJobs(); err != nil {
|
||||
return fmt.Errorf("error scheduling cleaner jobs: %w", err)
|
||||
}
|
||||
|
||||
// Schedule background subscriptions updating.
|
||||
if err := subscriptions.ScheduleJobs(); err != nil {
|
||||
return fmt.Errorf("error scheduling subscriptions jobs: %w", err)
|
||||
}
|
||||
|
||||
// Initialize the specialized workers pools.
|
||||
state.Workers.Client.Init(messages.ClientMsgIndices())
|
||||
state.Workers.Federator.Init(messages.FederatorMsgIndices())
|
||||
|
@ -318,7 +392,7 @@ func(context.Context, time.Time) {
|
|||
}
|
||||
|
||||
// Initialize metrics.
|
||||
if err := metrics.Initialize(state.DB); err != nil {
|
||||
if err := observability.InitializeMetrics(state.DB); err != nil {
|
||||
return fmt.Errorf("error initializing metrics: %w", err)
|
||||
}
|
||||
|
||||
|
@ -331,12 +405,19 @@ func(context.Context, time.Time) {
|
|||
HTTP router initialization
|
||||
*/
|
||||
|
||||
route, err = router.New(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating router: %s", err)
|
||||
// Close down the maintenance router.
|
||||
if err := route.Stop(); err != nil {
|
||||
return fmt.Errorf("error stopping maintenance router: %w", err)
|
||||
}
|
||||
|
||||
// Start preparing middleware stack.
|
||||
// Instantiate the main router.
|
||||
route, err = router.New(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating main router: %s", err)
|
||||
}
|
||||
|
||||
// Start preparing global middleware
|
||||
// stack (used for every request).
|
||||
middlewares := make([]gin.HandlerFunc, 1)
|
||||
|
||||
// RequestID middleware must run before tracing!
|
||||
|
@ -344,12 +425,12 @@ func(context.Context, time.Time) {
|
|||
|
||||
// Add tracing middleware if enabled.
|
||||
if config.GetTracingEnabled() {
|
||||
middlewares = append(middlewares, tracing.InstrumentGin())
|
||||
middlewares = append(middlewares, observability.TracingMiddleware())
|
||||
}
|
||||
|
||||
// Add metrics middleware if enabled.
|
||||
if config.GetMetricsEnabled() {
|
||||
middlewares = append(middlewares, metrics.InstrumentGin())
|
||||
middlewares = append(middlewares, observability.MetricsMiddleware())
|
||||
}
|
||||
|
||||
middlewares = append(middlewares, []gin.HandlerFunc{
|
||||
|
@ -418,30 +499,45 @@ func(context.Context, time.Time) {
|
|||
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
|
||||
)
|
||||
|
||||
// create required middleware
|
||||
// Create per-route / per-grouping middlewares.
|
||||
// rate limiting
|
||||
rlLimit := config.GetAdvancedRateLimitRequests()
|
||||
rlExceptions := config.GetAdvancedRateLimitExceptions()
|
||||
clLimit := middleware.RateLimit(rlLimit, rlExceptions) // client api
|
||||
s2sLimit := middleware.RateLimit(rlLimit, rlExceptions) // server-to-server (AP)
|
||||
fsMainLimit := middleware.RateLimit(rlLimit, rlExceptions) // fileserver / web templates
|
||||
fsEmojiLimit := middleware.RateLimit(rlLimit*2, rlExceptions) // fileserver (emojis only, use high limit)
|
||||
clLimit := middleware.RateLimit(rlLimit, config.GetAdvancedRateLimitExceptionsParsed()) // client api
|
||||
s2sLimit := middleware.RateLimit(rlLimit, config.GetAdvancedRateLimitExceptionsParsed()) // server-to-server (AP)
|
||||
fsMainLimit := middleware.RateLimit(rlLimit, config.GetAdvancedRateLimitExceptionsParsed()) // fileserver / web templates
|
||||
fsEmojiLimit := middleware.RateLimit(rlLimit*2, config.GetAdvancedRateLimitExceptionsParsed()) // fileserver (emojis only, use high limit)
|
||||
|
||||
// throttling
|
||||
cpuMultiplier := config.GetAdvancedThrottlingMultiplier()
|
||||
retryAfter := config.GetAdvancedThrottlingRetryAfter()
|
||||
clThrottle := middleware.Throttle(cpuMultiplier, retryAfter) // client api
|
||||
s2sThrottle := middleware.Throttle(cpuMultiplier, retryAfter)
|
||||
|
||||
// server-to-server (AP)
|
||||
fsThrottle := middleware.Throttle(cpuMultiplier, retryAfter) // fileserver / web templates / emojis
|
||||
pkThrottle := middleware.Throttle(cpuMultiplier, retryAfter) // throttle public key endpoint separately
|
||||
|
||||
// Robots http headers (x-robots-tag).
|
||||
//
|
||||
// robotsDisallowAll is used for client API + S2S endpoints
|
||||
// that definitely should never be indexed by crawlers.
|
||||
//
|
||||
// robotsDisallowAIOnly is used for utility endpoints,
|
||||
// fileserver, and for web endpoints that set their own
|
||||
// additional robots directives in HTML meta tags.
|
||||
//
|
||||
// Other endpoints like .well-known and nodeinfo handle
|
||||
// robots headers themselves based on configuration.
|
||||
robotsDisallowAll := middleware.RobotsHeaders("")
|
||||
robotsDisallowAIOnly := middleware.RobotsHeaders("aiOnly")
|
||||
|
||||
// Gzip middleware is applied to all endpoints except
|
||||
// fileserver (compression too expensive for those),
|
||||
// health (which really doesn't need compression), and
|
||||
|
@ -451,17 +547,18 @@ func(context.Context, time.Time) {
|
|||
|
||||
// these should be routed in order;
|
||||
// apply throttling *after* rate limiting
|
||||
authModule.Route(route, clLimit, clThrottle, gzip)
|
||||
clientModule.Route(route, clLimit, clThrottle, gzip)
|
||||
metricsModule.Route(route, clLimit, clThrottle)
|
||||
healthModule.Route(route, clLimit, clThrottle)
|
||||
fileserverModule.Route(route, fsMainLimit, fsThrottle)
|
||||
fileserverModule.RouteEmojis(route, instanceAccount.ID, fsEmojiLimit, fsThrottle)
|
||||
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)
|
||||
robotsModule.Route(route, fsMainLimit, fsThrottle, robotsDisallowAIOnly, gzip)
|
||||
wellKnownModule.Route(route, gzip, s2sLimit, s2sThrottle)
|
||||
nodeInfoModule.Route(route, s2sLimit, s2sThrottle, gzip)
|
||||
activityPubModule.Route(route, s2sLimit, s2sThrottle, gzip)
|
||||
activityPubModule.RoutePublicKey(route, s2sLimit, pkThrottle, gzip)
|
||||
webModule.Route(route, fsMainLimit, fsThrottle, gzip)
|
||||
activityPubModule.Route(route, s2sLimit, s2sThrottle, robotsDisallowAll, gzip)
|
||||
activityPubModule.RoutePublicKey(route, s2sLimit, pkThrottle, robotsDisallowAll, gzip)
|
||||
webModule.Route(route, fsMainLimit, fsThrottle, robotsDisallowAIOnly, gzip)
|
||||
|
||||
// Finally start the main http server!
|
||||
if err := route.Start(); err != nil {
|
||||
|
|
|
@ -20,11 +20,9 @@
|
|||
package testrig
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
@ -32,6 +30,7 @@
|
|||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/admin"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/cleaner"
|
||||
|
@ -40,15 +39,15 @@
|
|||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/language"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/metrics"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/middleware"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/observability"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/oidc"
|
||||
tlprocessor "github.com/superseriousbusiness/gotosocial/internal/processing/timeline"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/router"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/state"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/storage"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/subscriptions"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/timeline"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/tracing"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/typeutils"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/web"
|
||||
"github.com/superseriousbusiness/gotosocial/testrig"
|
||||
|
@ -128,13 +127,17 @@
|
|||
}
|
||||
config.SetInstanceLanguages(parsedLangs)
|
||||
|
||||
if err := tracing.Initialize(); err != nil {
|
||||
if err := observability.InitializeTracing(); err != nil {
|
||||
return fmt.Errorf("error initializing tracing: %w", err)
|
||||
}
|
||||
|
||||
// Initialize caches and database
|
||||
state.DB = testrig.NewTestDB(state)
|
||||
|
||||
// Set Actions on state, providing workers to
|
||||
// Actions as well for triggering side effects.
|
||||
state.AdminActions = admin.New(state.DB, &state.Workers)
|
||||
|
||||
// New test db inits caches so we don't need to do
|
||||
// that twice, we can just start the initialized caches.
|
||||
state.Caches.Start()
|
||||
|
@ -159,20 +162,13 @@
|
|||
testrig.StandardStorageSetup(state.Storage, "./testrig/media")
|
||||
|
||||
// build backend handlers
|
||||
transportController := testrig.NewTestTransportController(state, testrig.NewMockHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
r := io.NopCloser(bytes.NewReader([]byte{}))
|
||||
return &http.Response{
|
||||
StatusCode: 200,
|
||||
Body: r,
|
||||
Header: http.Header{
|
||||
"Content-Type": req.Header.Values("Accept"),
|
||||
},
|
||||
}, nil
|
||||
}, ""))
|
||||
httpClient := testrig.NewMockHTTPClient(nil, "./testrig/media")
|
||||
transportController := testrig.NewTestTransportController(state, httpClient)
|
||||
mediaManager := testrig.NewTestMediaManager(state)
|
||||
federator := testrig.NewTestFederator(state, transportController, mediaManager)
|
||||
|
||||
emailSender := testrig.NewEmailSender("./web/template/", nil)
|
||||
webPushSender := testrig.NewWebPushMockSender()
|
||||
typeConverter := typeutils.NewConverter(state)
|
||||
filter := visibility.NewFilter(state)
|
||||
|
||||
|
@ -196,14 +192,14 @@
|
|||
return fmt.Errorf("error starting list timeline: %s", err)
|
||||
}
|
||||
|
||||
processor := testrig.NewTestProcessor(state, federator, emailSender, mediaManager)
|
||||
processor := testrig.NewTestProcessor(state, federator, emailSender, webPushSender, mediaManager)
|
||||
|
||||
// Initialize workers.
|
||||
testrig.StartWorkers(state, processor.Workers())
|
||||
defer testrig.StopWorkers(state)
|
||||
|
||||
// Initialize metrics.
|
||||
if err := metrics.Initialize(state.DB); err != nil {
|
||||
if err := observability.InitializeMetrics(state.DB); err != nil {
|
||||
return fmt.Errorf("error initializing metrics: %w", err)
|
||||
}
|
||||
|
||||
|
@ -221,11 +217,11 @@
|
|||
middleware.AddRequestID(config.GetRequestIDHeader()), // requestID middleware must run before tracing
|
||||
}
|
||||
if config.GetTracingEnabled() {
|
||||
middlewares = append(middlewares, tracing.InstrumentGin())
|
||||
middlewares = append(middlewares, observability.TracingMiddleware())
|
||||
}
|
||||
|
||||
if config.GetMetricsEnabled() {
|
||||
middlewares = append(middlewares, metrics.InstrumentGin())
|
||||
middlewares = append(middlewares, observability.MetricsMiddleware())
|
||||
}
|
||||
|
||||
middlewares = append(middlewares, []gin.HandlerFunc{
|
||||
|
@ -292,6 +288,7 @@
|
|||
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
|
||||
|
@ -305,6 +302,7 @@
|
|||
healthModule.Route(route)
|
||||
fileserverModule.Route(route)
|
||||
fileserverModule.RouteEmojis(route, instanceAccount.ID)
|
||||
robotsModule.Route(route)
|
||||
wellKnownModule.Route(route)
|
||||
nodeInfoModule.Route(route)
|
||||
activityPubModule.Route(route)
|
||||
|
@ -314,11 +312,23 @@
|
|||
// Create background cleaner.
|
||||
cleaner := cleaner.New(state)
|
||||
|
||||
// Now schedule background cleaning tasks.
|
||||
// Schedule background cleaning tasks.
|
||||
if err := cleaner.ScheduleJobs(); err != nil {
|
||||
return fmt.Errorf("error scheduling cleaner jobs: %w", err)
|
||||
}
|
||||
|
||||
// Create subscriptions fetcher.
|
||||
subscriptions := subscriptions.New(
|
||||
state,
|
||||
transportController,
|
||||
typeConverter,
|
||||
)
|
||||
|
||||
// Schedule background subscriptions updating.
|
||||
if err := subscriptions.ScheduleJobs(); err != nil {
|
||||
return fmt.Errorf("error scheduling subscriptions jobs: %w", err)
|
||||
}
|
||||
|
||||
// Finally start the main http server!
|
||||
if err := route.Start(); err != nil {
|
||||
return fmt.Errorf("error starting router: %w", err)
|
||||
|
|
|
@ -41,5 +41,19 @@ func serverCommands() *cobra.Command {
|
|||
}
|
||||
config.AddServerFlags(serverStartCmd)
|
||||
serverCmd.AddCommand(serverStartCmd)
|
||||
|
||||
serverMaintenanceCmd := &cobra.Command{
|
||||
Use: "maintenance",
|
||||
Short: "start the gotosocial server in maintenance mode (returns 503 for almost all requests)",
|
||||
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(), server.Maintenance)
|
||||
},
|
||||
}
|
||||
config.AddServerFlags(serverMaintenanceCmd)
|
||||
serverCmd.AddCommand(serverMaintenanceCmd)
|
||||
|
||||
return serverCmd
|
||||
}
|
||||
|
|
|
@ -186,7 +186,7 @@ You'll need to put that file on your GoToSocial instance and make sure the file
|
|||
For this to work reliably, you should ensure that the [storage-local-base-path](../configuration/storage.md) in your GoToSocial configuration uses an absolute path. Otherwise you'll have to tweak the paths yourself.
|
||||
|
||||
```sh
|
||||
$ gotosocial admin media list-attachments --local-only | \
|
||||
$ gotosocial --config-path /path/to/config.yaml admin media list-attachments --local-only | \
|
||||
/path/to/media-to-borg-patterns.py \
|
||||
<storage-local-base-path>
|
||||
```
|
||||
|
@ -210,7 +210,7 @@ If you're running Borgmatic as a systemd service, you can [create a drop-in](htt
|
|||
|
||||
```ini
|
||||
[Service]
|
||||
ExecStartPre=/path/to/gotosocial admin media list-attachments --local-only | /path/to/media-to-borg-patterns.py <storage-local-base-path> /etc/borgmatic/gotosocial_patterns
|
||||
ExecStartPre=/path/to/gotosocial --config-path /path/to/config.yaml admin media list-attachments --local-only | /path/to/media-to-borg-patterns.py <storage-local-base-path> /etc/borgmatic/gotosocial_patterns
|
||||
```
|
||||
|
||||
Documentation that's good to review:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
GoToSocial supports 'blocking'/'suspending' domains that you don't want your instance to federate with. In our documentation, the two terms 'block' and 'suspend' are used interchangeably with regard to domains, because they mean the same thing: preventing your instance and the instance running on the target domain from communicating with one another, effectively cutting off federation between the two instances.
|
||||
|
||||
You can view, create, and remove domain blocks and domain allows using the [instance admin panel](./settings.md#federation).
|
||||
You can view, create, and remove domain blocks and domain allows using the [instance admin panel](./settings.md#domain-permissions).
|
||||
|
||||
This document focuses on what domain blocks actually *do* and what side effects are processed when you create a new domain block.
|
||||
|
||||
|
|
145
docs/admin/domain_permission_subscriptions.md
Normal file
145
docs/admin/domain_permission_subscriptions.md
Normal file
|
@ -0,0 +1,145 @@
|
|||
# Domain Permission Subscriptions
|
||||
|
||||
Via the [admin settings panel](./settings.md#subscriptions), you can create and manage domain permission subscriptions.
|
||||
|
||||
Domain permission subscriptions allow you to specify a URL at which a permission list is hosted. Every 24hrs at 11pm (by default), your instance will fetch and parse each list you're subscribed to, in order of priority (highest to lowest), and create domain permissions (or domain permission drafts) based on entries discovered in the lists.
|
||||
|
||||
Each domain permission subscription can be used to create domain allow or domain block entries.
|
||||
|
||||
!!! warning
|
||||
Currently, via blocklist subscriptions it is only possible to create "suspend" level domain blocks; other severities are not yet supported. Entries of severity "silence" or "limit" etc. on subscribed blocklists will be skipped.
|
||||
|
||||
## Priority
|
||||
|
||||
When you specify multiple domain permission subscriptions, they will be fetched and parsed in order of priority, from highest priority (255) to lowest priority (0).
|
||||
|
||||
Permissions discovered on lists higher up in the priority ranking will override permissions on lists lower down in the priority ranking.
|
||||
|
||||
For example, an instance admin subscribes to two allow lists, "Important List" at priority 255, and "Less Important List" at priority 128. Each of these subscribed lists contain an entry for `good-eggs.example.org`.
|
||||
|
||||
The subscription with the higher priority is the one that now creates and manages the domain allow entry for `good-eggs.example.org`.
|
||||
|
||||
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.
|
||||
|
||||
## 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.
|
||||
|
||||
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.
|
||||
|
||||
For example, an instance admin manually creates a domain block for the domain `horrid-trolls.example.org`. Later, they create a domain permission subscription for a block list that contains an entry for `horrid-trolls.example.org`, and they set "adopt orphans" to true. When their instance fetches and parses the list, and creates domain permission entries from it, then the orphan domain block for `horrid-trolls.example.org` gets adopted by the domain permission subscription. Now, if the domain permission subscription is removed, and the option to remove all permissions owned by the subscription is checked, then the domain block for `horrid-trolls.example.org` will also be removed.
|
||||
|
||||
## Fun Stuff To Do With Domain Permission Subscriptions
|
||||
|
||||
### 1. Create an allowlist-federation cluster.
|
||||
|
||||
Domain permission subscriptions make it possible to easily create allowlist-federation clusters, ie., a group of instances can essentially form their own mini-fediverse, wherein each instance runs in [allowlist federation mode](./federation_modes.md#allowlist-federation-mode), and subscribes to a cooperatively-managed allowlist hosted somewhere.
|
||||
|
||||
For example, instances `instance-a.example.org`, `instance-b.example.org`, and `instance-c.example.org` decide that they only want to federate with each other.
|
||||
|
||||
Using some version management platform like GitHub, they host a plaintext-formatted allowlist at something like `https://raw.githubusercontent.com/our-cluster/allowlist/refs/heads/main/allows.txt`.
|
||||
|
||||
The contents of the plaintext-formatted allowlist are as follows:
|
||||
|
||||
```text
|
||||
instance-a.example.org
|
||||
instance-b.example.org
|
||||
instance-c.example.org
|
||||
```
|
||||
|
||||
Each instance admin sets their federation mode to `allowlist`, and creates a subscription to create allows from `https://raw.githubusercontent.com/our-cluster/allowlist/refs/heads/main/allows.txt`, which results in domain allow entries being created for their own domain, and for each other domain in the cluster.
|
||||
|
||||
At some point, someone from `instance-d.example.org` asks (out of band) whether they can be added to the cluster. The existing admins agree, and update their plaintext-formatted allowlist to read:
|
||||
|
||||
```text
|
||||
instance-a.example.org
|
||||
instance-b.example.org
|
||||
instance-c.example.org
|
||||
instance-d.example.org
|
||||
```
|
||||
|
||||
The next time each instance fetches the list, a new domain allow entry will be created for `instance-d.example.org`, and it will be able to federate with the other domains on the list.
|
||||
|
||||
### 2. Cooperatively manage a blocklist.
|
||||
|
||||
Domain permission subscriptions make it easy to collaborate on and subscribe to shared blocklists of domains that host illegal / fashy / otherwise undesired accounts and content.
|
||||
|
||||
For example, the admins of instances `instance-e.example.org`, `instance-f.example.org`, and `instance-g.example.org` decide that they are tired of duplicating work by playing whack-a-mole with bad actors. To make their lives easier, they decide to collaborate on a shared blocklist.
|
||||
|
||||
Using some version management platform like GitHub, they host a blocklist at something like `https://raw.githubusercontent.com/baddies/blocklist/refs/heads/main/blocks.csv`.
|
||||
|
||||
When someone discovers a new domain hosting an instance they don't like, they can open a pull request or similar against the list, to add the questionable instance to the domain.
|
||||
|
||||
For example, someone gets an unpleasant reply from a new instance `fashy-arseholes.example.org`. Using their collaboration tools, they propose adding `fashy-arseholes.example.org` to the blocklist. After some deliberation and discussion, the domain is added to the list.
|
||||
|
||||
The next time each of `instance-e.example.org`, `instance-f.example.org`, and `instance-g.example.org` fetch the block list, a block entry will be created for ``fashy-arseholes.example.org``.
|
||||
|
||||
### 3. Subscribe to a blocklist, but ignore some of it.
|
||||
|
||||
Say that `instance-g.example.org` in the previous section decides that they agree with most of the collaboratively-curated blocklist, but they actually would like to keep federating with ``fashy-arseholes.example.org`` for some godforsaken reason.
|
||||
|
||||
This can be done in one of three ways:
|
||||
|
||||
1. The admin of `instance-g.example.org` subscribes to the shared blocklist, but they do so with the ["create as drafts"](./settings.md#create-permissions-as-drafts) option set to true. When their instance fetches the blocklist, a draft block is created for `fashy-arseholes.example.org`. The admin of `instance-g` just leaves the permission as a draft, or rejects it, so it never comes into force.
|
||||
2. Before the blocklist is re-fetched, the admin of `instance-g.example.org` creates a [domain permission exclude](./settings.md#excludes) entry for ``instance-g.example.org``. The domain ``instance-g.example.org`` then becomes exempt/excluded from automatic permission creation, and so the block for ``instance-g.example.org`` on the shared blocklist does not get created in the database of ``instance-g.example.org`` the next time the list is fetched.
|
||||
3. The admin of `instance-g.example.org` creates an explicit domain allow entry for `fashy-arseholes.example.org` on their own instance. Because their instance is running in `blocklist` federation mode, [the explicit allow overrides the domain block entry](./federation_modes.md#in-blocklist-mode), and so the domain remains unblocked.
|
||||
|
||||
### 4. Subscribe directly to another instance's blocklist.
|
||||
|
||||
Because GoToSocial is able to fetch and parse JSON-formatted lists of domain permissions, it is possible to subscribe directly to another instance's list of blocked domains via their `/api/v1/instance/domain_blocks` (Mastodon) or `/api/v1/instance/peers?filter=suspended` (GoToSocial) endpoint (if exposed).
|
||||
|
||||
For example, the Mastodon instance `peepee.poopoo.example.org` exposes their block list publicly, and the owner of the GoToSocial instance `instance-h.example.org` decides they quite like the cut of the Mastodon moderator's jib. They create a domain permission subscription of type JSON, and set the URI to `https://peepee.poopoo.example.org/api/v1/instance/domain_blocks`. Every 24 hours, their instance will go fetch the blocklist JSON from the Mastodon instance, and create permissions based on entries discovered therein.
|
||||
|
||||
## Example lists per content type
|
||||
|
||||
Shown below are examples of the different permission list formats that GoToSocial is able to understand and parse.
|
||||
|
||||
Each list contains three domains, `bumfaces.net`, `peepee.poopoo`, and `nothanks.com`.
|
||||
|
||||
### CSV
|
||||
|
||||
CSV lists use content type `text/csv`.
|
||||
|
||||
Mastodon domain permission exports generally use this format.
|
||||
|
||||
```csv
|
||||
#domain,#severity,#reject_media,#reject_reports,#public_comment,#obfuscate
|
||||
bumfaces.net,suspend,false,false,big jerks,false
|
||||
peepee.poopoo,suspend,false,false,harassment,false
|
||||
nothanks.com,suspend,false,false,,false
|
||||
```
|
||||
|
||||
### JSON (application/json)
|
||||
|
||||
JSON lists use content type `application/json`.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"domain": "bumfaces.net",
|
||||
"suspended_at": "2020-05-13T13:29:12.000Z",
|
||||
"public_comment": "big jerks"
|
||||
},
|
||||
{
|
||||
"domain": "peepee.poopoo",
|
||||
"suspended_at": "2020-05-13T13:29:12.000Z",
|
||||
"public_comment": "harassment"
|
||||
},
|
||||
{
|
||||
"domain": "nothanks.com",
|
||||
"suspended_at": "2020-05-13T13:29:12.000Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Plaintext (text/plain)
|
||||
|
||||
Plaintext lists use content type `text/plain`.
|
||||
|
||||
Note that it is not possible to include any fields like "obfuscate" or "public comment" in plaintext lists, as they are simply a newline-separated list of domains.
|
||||
|
||||
```text
|
||||
bumfaces.net
|
||||
peepee.poopoo
|
||||
nothanks.com
|
||||
```
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
GoToSocial serves a `robots.txt` file on the host domain. This file contains rules that attempt to block known AI scrapers, as well as some other indexers. It also includes some rules to ensure things like API endpoints aren't indexed by search engines since there really isn't any point to them.
|
||||
|
||||
## Allow/disallow stats collection
|
||||
|
||||
You can allow or disallow crawlers from collecting stats about your instance from the `/nodeinfo/2.0` and `/nodeinfo/2.1` endpoints by changing the setting `instance-stats-mode`, which modifies the `robots.txt` file. See [instance configuration](../configuration/instance.md) for more details.
|
||||
|
||||
## AI scrapers
|
||||
|
||||
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!
|
||||
|
|
|
@ -34,11 +34,11 @@ Clicking on the username of the reported account opens that account in the 'Acco
|
|||
|
||||
You can use this section to search for an account and perform moderation actions on it.
|
||||
|
||||
### Federation
|
||||
### Domain Permissions
|
||||
|
||||

|
||||
|
||||
In the federation section you can create, delete, and review explicit domain blocks and domain allows.
|
||||
In the domain permissions section you can create, delete, and review domain blocks, domain allows, drafts, excludes, and subscriptions.
|
||||
|
||||
For more detail on federation settings, and specifically how domain allows and domain blocks work in combination, please see [the federation modes section](./federation_modes.md), and [the domain blocks section](./domain_blocks.md).
|
||||
|
||||
|
@ -46,20 +46,99 @@ For more detail on federation settings, and specifically how domain allows and d
|
|||
|
||||
You can enter a domain to suspend in the search field, which will filter the list to show you if you already have a block for it.
|
||||
|
||||
Clicking 'suspend' gives you a form to add a public and/or private comment, and submit to add the block. Adding a suspension will suspend all the currently known accounts on the instance, and prevent any new interactions with any user on the blocked instance.
|
||||
Clicking 'suspend' gives you a form to add a public and/or private comment, and submit to add the block.
|
||||
|
||||
Adding a domain block will suspend all currently known accounts from that domain, and prevent any new interactions with the blocked domain.
|
||||
|
||||
#### Domain Allows
|
||||
|
||||
The domain allows section works much like the domain blocks section, described above, only for explicit domain allows rather than domain blocks.
|
||||
|
||||
#### Bulk import/export
|
||||
#### Import/export
|
||||
|
||||
Through the link at the bottom of the Federation section (or going to `/settings/admin/federation/import-export`) you can do bulk import/export of blocklists and allowlists.
|
||||
In this section you can do bulk import/export of domain permissions in JSON, CSV, or plaintext formats.
|
||||
|
||||

|
||||
|
||||
Upon importing a list, either through the input field or from a file, you can review the entries in the list before importing a subset. You'll also be warned for entries that use subdomains, providing an easy way to change them to the main domain.
|
||||
|
||||
#### Drafts
|
||||
|
||||
In this section you can create, search through, accept, and reject domain permission drafts.
|
||||
|
||||
Domain permission drafts are domain permissions that have been proposed (either via manual creation or as an entry from a subscribed block / allow list), but have not yet come into force.
|
||||
|
||||
Until it is accepted, a domain permission draft will not have any effect on federation with the domain it targets. Upon acceptance, it will be converted into either a domain block or a domain allow, and start being enforced.
|
||||
|
||||
#### Excludes
|
||||
|
||||
In this section, you can create, search through, and remove domain permission excludes.
|
||||
|
||||
Domain permission excludes prevent permissions for a domain (and all subdomains) from being automatically managed by domain permission subscriptions.
|
||||
|
||||
For example, if you create an exclude entry for the domain `example.org`, then a blocklist or allowlist subscription will exclude entries for `example.org` and any of its subdomains (`sub.example.org`, `another.sub.example.org` etc.) when creating domain permission drafts and domain blocks/allows.
|
||||
|
||||
This functionality allows you to manually manage permissions for excluded domains, in cases where you know you definitely do or don't want to federate with a given domain, no matter what entries are contained in a domain permission subscription.
|
||||
|
||||
Note that by itself, creation of an exclude entry for a given domain does not affect federation with that domain at all, it is only useful in combination with permission subscriptions.
|
||||
|
||||
#### Subscriptions
|
||||
|
||||
In this section, you can create, search through, edit, test, and remove domain permission subscriptions.
|
||||
|
||||
Domain permission subscriptions allow you to specify a URL at which a permission list is hosted. Every 24hrs at 11pm (by default), your instance will fetch and parse each subscribed list, and create domain permissions (or domain permission drafts) based on entries in the lists.
|
||||
|
||||
##### Title
|
||||
|
||||
You can optionally use the title field to set a title for the subscription, as a reminder for yourself and other admins.
|
||||
|
||||
For example, you might subscribe to a list at `https://lists.example.org/baddies.csv` and set the title of the subscription to something that reflects the contents of that list, such as "Basic block list (worst of the worst)", or similar.
|
||||
|
||||
##### Subscription Priority
|
||||
|
||||
When you specify multiple domain permission subscriptions, they will be fetched and parsed in order of priority, from highest priority (255) to lowest priority (0).
|
||||
|
||||
Permissions discovered on lists higher up in the priority ranking will override permissions on lists lower down in the priority ranking.
|
||||
|
||||
For more information on priority, please see the separate [domain permission subscriptions](./domain_permission_subscriptions.md) document.
|
||||
|
||||
##### Permission Type
|
||||
|
||||
You can use this dropdown to select whether permissions discovered at the list URL should be created as domain blocks, or domain allows.
|
||||
|
||||
##### Content Type
|
||||
|
||||
You can use this dropdown to select the content type of the list at the subscribed URL.
|
||||
|
||||
Use CSV for Mastodon-style permission lists, plain for plaintext lists of domain names, or JSON for json-exported lists.
|
||||
|
||||
##### Basic Auth
|
||||
|
||||
Check this box to provide a basic auth username and/or password credential for the subscribed list, which will be sent along with each request to fetch the list.
|
||||
|
||||
##### Adopt Orphan Permissions
|
||||
|
||||
If you check this box, then any existing domain permissions will become managed by this subscription in the following circumstances:
|
||||
|
||||
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.
|
||||
|
||||
##### Create Permissions as Drafts
|
||||
|
||||
With this box checked (default), any permissions created by this subscription will be created as **drafts** which require manual approval to come into force.
|
||||
|
||||
It is recommended to leave this box checked unless you absolutely trust the subscribed list, to avoid inadvertent blocking or allowing of domains you'd rather not block or allow.
|
||||
|
||||
##### Test a Subscription
|
||||
|
||||
To test whether a subscription can be successfully parsed, first create the subscription, then in the detailed view for that subscription, click on the "Test" button.
|
||||
|
||||
If your instance is able to fetch and parse permissions at the subscription URI, then you will see a list of these after clicking "Test". Otherwise, you will see an error message.
|
||||
|
||||

|
||||
|
||||
## Administration
|
||||
|
||||
Instance administration settings.
|
||||
|
@ -174,4 +253,4 @@ custom CSS allows you to further customize the way your instance looks when visi
|
|||
|
||||
This custom CSS will be applied to all pages of your instance. Users themes and CSS still take precedence over this customization.
|
||||
|
||||
See the [Custom CSS](./custom_css.md) page for some tips on writing custom CSS for your instance.
|
||||
See the [Custom CSS](../user_guide/custom_css.md) page for some tips on writing custom CSS for your instance.
|
||||
|
|
|
@ -46,12 +46,14 @@ If you **reject** the sign-up, you may wish to inform the applicant that their s
|
|||
|
||||
## Sign-Up Limits
|
||||
|
||||
To avoid sign-up backlogs overwhelming admins and moderators, GoToSocial limits the sign-up pending backlog to 20 accounts. Once there are 20 accounts pending in the backlog waiting to be handled by an admin or moderator, new sign-ups will not be accepted via the form.
|
||||
By default, to avoid sign-up backlogs overwhelming admins and moderators, GoToSocial limits the sign-up pending backlog to 20 accounts. Once there are 20 accounts pending in the backlog waiting to be handled by an admin or moderator, new sign-ups will not be accepted via the form.
|
||||
|
||||
New sign-ups will also not be accepted via the form if 10 or more new account sign-ups have been approved in the last 24 hours, to avoid instances rapidly expanding beyond the capabilities of moderators.
|
||||
By default, new sign-ups will also not be accepted via the form if 10 or more new account sign-ups have been approved in the last 24 hours, to avoid instances rapidly expanding beyond the capabilities of moderators.
|
||||
|
||||
In both cases, applicants will be shown an error message explaining why they could not submit the form, and inviting them to try again later.
|
||||
|
||||
The limit of sign-ups per day, and the backlog size, can be configured or disabled altogether with the variables `accounts-registration-daily-limit` and `accounts-registration-backlog-limit`. See the [accounts config section](../configuration/accounts.md) for more info.
|
||||
|
||||
To combat spam accounts, GoToSocial account sign-ups **always** require manual approval by an administrator, and applicants must **always** confirm their email address before they are able to log in and post.
|
||||
|
||||
## Sign-Up Via Invite
|
||||
|
|
|
@ -8,7 +8,6 @@ We need to register a new application, which we can then use to request an OAuth
|
|||
|
||||
```bash
|
||||
curl \
|
||||
-X POST \
|
||||
-H 'Content-Type:application/json' \
|
||||
-d '{
|
||||
"client_name": "your_app_name",
|
||||
|
@ -89,7 +88,6 @@ You can do this with another `POST` request that looks like the following:
|
|||
|
||||
```bash
|
||||
curl \
|
||||
-X POST \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
|
||||
|
|
|
@ -24,11 +24,11 @@ In case the rate limit is exceeded, an [HTTP 429 Too Many Requests](https://deve
|
|||
|
||||
### My rate limit keeps being exceeded! Why?
|
||||
|
||||
If you find that your rate limit is regularly being exceeded (both for yourself and other callers) during normal use of your instance, it may be that GoToSocial can't tell the clients apart by IP address. You can investigate this by viewing the logs of your instance. If (almost) all logged IP addresses appear to be the same IP address (something like `172.x.x.x`), then the rate limiting will cause problems.
|
||||
If you find that your rate limit is regularly being exceeded (both for yourself and other callers) during normal use of your instance, it may be that GoToSocial can't tell the clients apart by IP address. You can investigate this by viewing the logs of your instance. If (almost) all logged client IP addresses appear to be the same IP address (something like `172.x.x.x`), then the rate limiting will cause problems.
|
||||
|
||||
This happens when your server is running inside NAT (port forwarding), or behind an HTTP proxy without the correct configuration, causing your instance to see all incoming IP addresses as the same address: namely, the IP address of your reverse proxy or gateway. This means that all incoming requests are *sharing the same rate limit*, rather than being split correctly per IP.
|
||||
|
||||
If you are using an HTTP proxy then it's likely that your `trusted-proxies` is not correctly configured. If this is the case, try adding the IP address of your reverse proxy to the list of `trusted-proxies`, and restarting your instance.
|
||||
If you are using an HTTP proxy then it's likely that your `trusted-proxies` is not correctly configured. See the [trusted-proxies](../configuration/trusted_proxies.md) documentation for more info on how to resolve this.
|
||||
|
||||
If you don't have an HTTP proxy, then it's likely caused by NAT. In this case you should disable rate limiting altogether.
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -20,6 +20,28 @@ accounts-registration-open: false
|
|||
# Default: true
|
||||
accounts-reason-required: true
|
||||
|
||||
# Int. Number of approved sign-ups allowed within
|
||||
# 24hrs before new account registration is closed.
|
||||
#
|
||||
# Leaving this count at the default essentially limits
|
||||
# your instance to growing by 10 accounts per day.
|
||||
#
|
||||
# Setting this number to 0 or less removes the limit.
|
||||
#
|
||||
# Default: 10
|
||||
accounts-registration-daily-limit: 10
|
||||
|
||||
# Int. Number of new account sign-ups allowed in the pending
|
||||
# approval queue before new account registration is closed.
|
||||
#
|
||||
# This can be used to essentially "throttle" the sign-up
|
||||
# queue to prevent instance admins becoming overwhelmed.
|
||||
#
|
||||
# Setting this number to 0 or less removes the limit.
|
||||
#
|
||||
# Default: 20
|
||||
accounts-registration-backlog-limit: 20
|
||||
|
||||
# Bool. Allow accounts on this instance to set custom CSS for their profile pages and statuses.
|
||||
# Enabling this setting will allow accounts to upload custom CSS via the /user settings page,
|
||||
# which will then be rendered on the web view of the account's profile and statuses.
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# General
|
||||
|
||||
The top-level configuration for GoToSocial, including basic things like host, port, bind address and transport protocol.
|
||||
|
||||
The only things you *really* need to set here are `host`, which should be the hostname where your instance is reachable, and probably `port`.
|
||||
The top-level configuration for GoToSocial, including basic things like host, port, bind address, and trusted-proxies.
|
||||
|
||||
## Settings
|
||||
|
||||
|
|
|
@ -128,4 +128,60 @@ instance-deliver-to-shared-inboxes: true
|
|||
# Options: [true, false]
|
||||
# Default: false
|
||||
instance-inject-mastodon-version: false
|
||||
|
||||
# String. 24hr time of day formatted as hh:mm.
|
||||
# Examples: ["14:30", "00:00", "04:00"]
|
||||
# Default: "23:00" (11pm).
|
||||
instance-subscriptions-process-from: "23:00"
|
||||
|
||||
# Duration. Period between subscription updates.
|
||||
# Examples: ["24h", "72h", "12h"]
|
||||
# Default: "24h" (once per day).
|
||||
instance-subscriptions-process-every: "24h"
|
||||
|
||||
# String. Allows you to customize if and how stats are served to
|
||||
# crawlers at the /api/v1|v2/instance and /nodeinfo endpoints.
|
||||
#
|
||||
# Note that no matter what you set below, the /api/v1|v2/instance
|
||||
# endpoints will not be allowed by robots.txt, as these are client
|
||||
# API endpoints.
|
||||
#
|
||||
# "" / empty string (default mode): Serve accurate stats at instance
|
||||
# and nodeinfo endpoints, and DISALLOW crawlers from crawling
|
||||
# those endpoints in robots.txt. This mode is equivalent to politely
|
||||
# asking crawlers not to crawl, but there's no guarantee they will obey,
|
||||
# as unfortunately many crawlers don't even check robots.txt.
|
||||
#
|
||||
# "zero": Serve zeroed-out stats at instance and nodeinfo endpoints,
|
||||
# and DISALLOW crawlers from crawling those endpoints in robots.txt.
|
||||
# This mode prevents even ill-behaved crawlers from gathering stats
|
||||
# about your instance, as all gathered values will be 0. This is the
|
||||
# safest way of preserving your instance's privacy in terms of stats.
|
||||
#
|
||||
# "serve": Serve accurate stats at instance and nodeinfo endpoints,
|
||||
# and ALLOW crawlers to crawl those endpoints. This mode is useful
|
||||
# if you want to contribute to fediverse statistics collection projects.
|
||||
#
|
||||
# "baffle": Serve randomized, preposterous stats at instance and nodeinfo
|
||||
# endpoints, and DISALLOW crawlers from crawling those endpoints in robots.txt.
|
||||
# This mode can be useful to annoy crawlers that don't respect robots.txt.
|
||||
# Warning that this may draw the ire of crawler implementers who don't
|
||||
# respect robots.txt, and may therefore put a target on your instance.
|
||||
#
|
||||
# Options: ["", "zero", "serve", "baffle"]
|
||||
# Default: ""
|
||||
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.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Options: [true, false]
|
||||
# Default: true
|
||||
instance-allow-backdating-statuses: true
|
||||
```
|
||||
|
|
171
docs/configuration/trusted_proxies.md
Normal file
171
docs/configuration/trusted_proxies.md
Normal file
|
@ -0,0 +1,171 @@
|
|||
# Trusted Proxies
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
## tl;dr: How to set `trusted-proxies` correctly
|
||||
|
||||
If your `trusted-proxies` setting is not correctly configured, you may see the following warning on the web view of your instance (v0.18.0 and above):
|
||||
|
||||
> Warning! It looks like trusted-proxies is not set correctly in this instance's configuration. This may cause rate-limiting issues and, by extension, federation issues.
|
||||
>
|
||||
> If you are the instance admin, you should fix this by adding `SUGGESTED_IP_RANGE` to your trusted-proxies.
|
||||
|
||||
To resolve this, copy the IP range in the message, and edit your `config.yaml` file to add the IP range to your `trusted-proxies`.
|
||||
|
||||
!!! tip "You may be getting rate limited even if you don't see the above warning!"
|
||||
If you're on a version of GoToSocial below v0.18.0, or you're running behind a CDN such as Cloudflare (not recommended), you won't see a warning message. Instead, you'll see in your GoToSocial logs that all client IPs are the same address. In this case, take the recurring client IP value as `SUGGESTED_IP_RANGE`.
|
||||
|
||||
In this example, we assume `SUGGESTED_IP_RANGE` to be `172.17.0.1/16` (the default Docker bridge network subnet).
|
||||
|
||||
Before (default config):
|
||||
|
||||
```yaml
|
||||
trusted-proxies:
|
||||
- "127.0.0.1/32"
|
||||
- "::1"
|
||||
```
|
||||
|
||||
After (new config):
|
||||
|
||||
```yaml
|
||||
trusted-proxies:
|
||||
- "172.17.0.1/16"
|
||||
- "127.0.0.1/32"
|
||||
- "::1"
|
||||
```
|
||||
|
||||
If you are using [environment variables](../configuration/index.md#environment-variables) to configure your instance, you can configure `trusted-proxies` by setting the environment variable `GTS_TRUSTED_PROXIES` to a comma-separated list of IP ranges, like so:
|
||||
|
||||
```env
|
||||
GTS_TRUSTED_PROXIES="172.17.0.1/16,127.0.0.1/32,::1"
|
||||
```
|
||||
|
||||
If you are using docker compose, your docker-compose.yaml file should look something like this after the change (note that yaml uses `: ` and not `=`):
|
||||
|
||||
```yaml
|
||||
################################
|
||||
# BLAH BLAH OTHER CONFIG STUFF #
|
||||
################################
|
||||
environment:
|
||||
############################
|
||||
# BLAH BLAH OTHER ENV VARS #
|
||||
############################
|
||||
## For reverse proxy setups:
|
||||
GTS_TRUSTED_PROXIES: "172.17.0.1/16,127.0.0.1/32,::1"
|
||||
################################
|
||||
# BLAH BLAH OTHER CONFIG STUFF #
|
||||
################################
|
||||
```
|
||||
|
||||
Once you have made the necessary configuration changes, **restart your instance** and refresh the home page.
|
||||
|
||||
If the message is gone, then the problem is resolved!
|
||||
|
||||
If you still see the warning message but with a different suggested IP range to add to `trusted-proxies`, then follow the same steps as above again, including the new suggested IP range in your config in addition to the one you just added.
|
||||
|
||||
!!! tip "Cloudflare IP Addresses"
|
||||
If you are running with a CDN/proxy such as Cloudflare in front of your GoToSocial instance (not recommended), then you may need to add one or more of the Cloudflare IP addresses to your `trusted-proxies` in order to have rate limiting work properly. You can find a list of Cloudflare IP addresses here: https://www.cloudflare.com/ips/
|
||||
|
||||
## I can't seem to get `trusted-proxies` configured properly, can I just disable the warning?
|
||||
|
||||
There are some situations where it's not practically possible to get `trusted-proxies` configured correctly to detect the real client IP of incoming requests, or where the real client IP is accurate but still shows as being within a private network.
|
||||
|
||||
For example, if you're running GoToSocial on your home network, behind a home internet router that cannot inject an `X-Forwarded-For` header, then your suggested entry to add to `trusted-proxies` will look something like `192.168.x.x`, but adding this to `trusted-proxies` won't resolve the issue.
|
||||
|
||||
Another example: you're running GoToSocial on your home network, behind a home internet router, and you are accessing the web frontend from a device that's *also* on your home network, like your laptop or phone. In this case, your router may send you directly to your GoToSocial instance without your request ever leaving the network, and so GtS will correctly see *your* client IP address as a private network address, but *other* requests coming in from the wider internet will show their real remote client IP addresses. In this scenario, the `trusted-proxies` warning does not really apply.
|
||||
|
||||
If you've tried editing your `trusted-proxies` setting, but you still see the warning, then it's likely that one of the above examples applies to you. You can proceed in one of two ways:
|
||||
|
||||
### Add specific exception for your home network (preferred)
|
||||
|
||||
If the suggested IP range in the `trusted-proxies` warning looks something like `192.168.x.x`, but you still see other client IPs in your GoToSocial logs that don't start with `192.168`, then try adding a rate limiting exception only for devices on your home network, while leaving rate limiting in place for outside IP addresses.
|
||||
|
||||
For example, if your suggestion is something like `192.168.1.128/32`, then swap the `/32` for `/24` so that the range covers `192.168.1.0` -> `192.168.1.255`, and add this to the `advanced-rate-limit-exceptions` setting in your `config.yaml` file.
|
||||
|
||||
Before (default config):
|
||||
|
||||
```yaml
|
||||
advanced-rate-limit-exceptions: []
|
||||
```
|
||||
|
||||
After (new config):
|
||||
|
||||
```yaml
|
||||
advanced-rate-limit-exceptions:
|
||||
- "192.168.1.128/24"
|
||||
```
|
||||
|
||||
If you are using [environment variables](../configuration/index.md#environment-variables) to configure your instance, you can configure `advanced-rate-limit-exceptions` by setting the environment variable `GTS_ADVANCED_RATE_LIMIT_EXCEPTIONS` to a comma-separated list of IP ranges, like so:
|
||||
|
||||
```env
|
||||
GTS_ADVANCED_RATE_LIMIT_EXCEPTIONS="192.168.1.128/24"
|
||||
```
|
||||
|
||||
If you are using docker compose, your docker-compose.yaml file should look something like this after the change (note that yaml uses `: ` and not `=`):
|
||||
|
||||
```yaml
|
||||
################################
|
||||
# BLAH BLAH OTHER CONFIG STUFF #
|
||||
################################
|
||||
environment:
|
||||
############################
|
||||
# BLAH BLAH OTHER ENV VARS #
|
||||
############################
|
||||
GTS_ADVANCED_RATE_LIMIT_EXCEPTIONS: "192.168.1.128/24"
|
||||
################################
|
||||
# BLAH BLAH OTHER CONFIG STUFF #
|
||||
################################
|
||||
```
|
||||
|
||||
Once you have made the necessary configuration changes, **restart your instance** and refresh the home page.
|
||||
|
||||
### Turn off rate limiting entirely (last resort)
|
||||
|
||||
If nothing else works, you can disable rate limiting entirely, which will also disable the `trusted-proxies` check and warning.
|
||||
|
||||
!!! warning
|
||||
Turning off rate limiting entirely should be considered a last resort, as rate limiting helps protect your instance from spam and scrapers.
|
||||
|
||||
To turn off rate limiting, set `advanced-rate-limit-requests` to 0 in your `config.yaml`.
|
||||
|
||||
Before (default config):
|
||||
|
||||
```yaml
|
||||
advanced-rate-limit-requests: 300
|
||||
```
|
||||
|
||||
After (new config):
|
||||
|
||||
```yaml
|
||||
advanced-rate-limit-requests: 0
|
||||
```
|
||||
|
||||
If you are using [environment variables](../configuration/index.md#environment-variables) to configure your instance, you can configure `advanced-rate-limit-requests` by setting the environment variable `GTS_ADVANCED_RATE_LIMIT_REQUESTS` to 0, like so:
|
||||
|
||||
```env
|
||||
GTS_ADVANCED_RATE_LIMIT_REQUESTS="0"
|
||||
```
|
||||
|
||||
If you are using docker compose, your docker-compose.yaml file should look something like this after the change (note that yaml uses `: ` and not `=`):
|
||||
|
||||
```yaml
|
||||
################################
|
||||
# BLAH BLAH OTHER CONFIG STUFF #
|
||||
################################
|
||||
environment:
|
||||
############################
|
||||
# BLAH BLAH OTHER ENV VARS #
|
||||
############################
|
||||
GTS_ADVANCED_RATE_LIMIT_REQUESTS: "0"
|
||||
################################
|
||||
# BLAH BLAH OTHER CONFIG STUFF #
|
||||
################################
|
||||
```
|
||||
|
||||
Once you have made the necessary configuration changes, **restart your instance** and refresh the home page.
|
|
@ -1,5 +1,13 @@
|
|||
# Actors and Actor Properties
|
||||
|
||||
## `Service` vs `Person` actors
|
||||
|
||||
GoToSocial serves most accounts as the ActivityStreams `Person` type described [here](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person).
|
||||
|
||||
Accounts that users have selected to mark as bot accounts, however, will use the `Service` type described [here](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-service).
|
||||
|
||||
This type distinction can be used by remote servers to distinguish between bot accounts and "regular" user accounts.
|
||||
|
||||
## Inbox
|
||||
|
||||
GoToSocial implements Inboxes for Actors following the ActivityPub specification [here](https://www.w3.org/TR/activitypub/#inbox).
|
||||
|
|
|
@ -47,6 +47,60 @@ The `href` URL provided by GoToSocial in outgoing tags points to a web URL that
|
|||
|
||||
GoToSocial makes no guarantees whatsoever about what the content of the given `text/html` will be, and remote servers should not interpret the URL as a canonical ActivityPub ID/URI property. The `href` URL is provided merely as an endpoint which *might* contain more information about the given hashtag.
|
||||
|
||||
## Emojis
|
||||
|
||||
GoToSocial uses the `http://joinmastodon.org/ns#Emoji` type to allow users to add custom emoji to their posts.
|
||||
|
||||
For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"@context": [
|
||||
"https://gotosocial.org/ns",
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
{
|
||||
"Emoji": "toot:Emoji",
|
||||
"sensitive": "as:sensitive",
|
||||
"toot": "http://joinmastodon.org/ns#"
|
||||
}
|
||||
],
|
||||
"type": "Note",
|
||||
"content": "<p>here's a stinky creature -> :shocked_pikachu:</p>",
|
||||
[...],
|
||||
"tag": {
|
||||
"icon": {
|
||||
"mediaType": "image/png",
|
||||
"type": "Image",
|
||||
"url": "https://example.org/fileserver/01BPSX2MKCRVMD4YN4D71G9CP5/emoji/original/01AZY1Y5YQD6TREB5W50HGTCSZ.png"
|
||||
},
|
||||
"id": "https://example.org/emoji/01AZY1Y5YQD6TREB5W50HGTCSZ",
|
||||
"name": ":shocked_pikachu:",
|
||||
"type": "Emoji",
|
||||
"updated": "2022-11-17T11:36:05Z"
|
||||
}
|
||||
[...]
|
||||
}
|
||||
```
|
||||
|
||||
The text `:shocked_pikachu:` in the `content` of the above `Note` should be replaced by clients with a small (inline) version of the emoji image, when rendering the `Note` and displaying it to users.
|
||||
|
||||
The `updated` and `icon.url` properties of the emoji can be used by remote instances to determine whether their representation of the GoToSocial emoji image is up to date.
|
||||
|
||||
The `Emoji` can also be dereferenced at its `id` URI if necessary, so that remotes can check whether their cached version of the emoji metadata is up to date.
|
||||
|
||||
By default, GoToSocial sets a 50kb limit on the size of emoji images that can be uploaded and sent out, and a 100kb limit on the size of emoji images that can be federated in, though both of these settings are configurable by users.
|
||||
|
||||
GoToSocial can send and receive emoji images of the type `image/png`, `image/jpeg`, `image/gif`, and `image/webp`.
|
||||
|
||||
!!! info
|
||||
Note that the `tag` property can be either an array of objects, or a single object.
|
||||
|
||||
### `null` / empty `id` property
|
||||
|
||||
Some server softwares like Akkoma include emojis as [anonymous objects](https://www.w3.org/TR/activitypub/#obj-id) on statuses. That is, they set the `id` property to the value `null` to indicate that the emoji cannot be dereferenced at any specific endpoint.
|
||||
|
||||
When receiving such emojis, GoToSocial will generate a dummy id for that emoji in its database in the form `https://[host]/dummy_emoji_path?shortcode=[shortcode]`, for example, `https://example.org/dummy_emoji_path?shortcode=shocked_pikachu`.
|
||||
|
||||
## Mentions
|
||||
|
||||
GoToSocial users can Mention other users in their posts, using the common `@[username]@[domain]` format. For example, if a GoToSocial user wanted to mention user `someone` on instance `example.org`, they could do this by including `@someone@example.org` in their post somewhere.
|
||||
|
|
|
@ -41,3 +41,7 @@ We have guides available for the following servers:
|
|||
When using a reverse-proxy, special care must be taken to allow WebSockets to work too. This is necessary as many client applications use WebSockets to stream your timeline. WebSockets is not used as part of federation.
|
||||
|
||||
Make sure you read the [WebSocket](websocket.md) documentation and configure your reverse proxy accordingly.
|
||||
|
||||
## Trusted Proxies
|
||||
|
||||
When using a reverse-proxy, you may run into issues with rate limiting and `trusted-proxies`. Check the [trusted proxies](../../configuration/trusted_proxies.md) documentation if you have any problems.
|
||||
|
|
|
@ -134,14 +134,14 @@ GoToSocial CLI 工具还提供了从实例备份和恢复数据的命令,这
|
|||
* 备份是加密的。
|
||||
* 内置工具可以列出快照并从中恢复。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
[Rsync.net](https://rsync.net/)、[BorgBase](https://www.borgbase.com/) 和 [Hetzner Storage](https://www.hetzner.com/storage/storage-box) 提供了可用于备份的经济实惠的存储。Rsync.net 有一种专门为 Borg 设计的备份产品,比他们的常规存储产品便宜得多。如果你只想使用 Borg 管理的备份,请在[此处注册](https://www.rsync.net/products/borg.html)。
|
||||
|
||||
#### Borgmatic
|
||||
|
||||
[Borgmatic](https://torsion.org/borgmatic/) 是一个帮助使用 [Borg](https://www.borgbackup.org/) 进行备份的工具。它通过使用 YAML 的声明性配置文件驱动。BorgBase、Rsync.net 和 Hetzner 都支持 Borg。
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
初始化 Borg 仓库时,确保使用强加密密钥进行设置,并将密钥安全地存放在某处。否则将无法在将来解密备份。ArchWiki 上关于 Borgmatic 的条目解释了如何安全地将你的加密密钥传递给 Borgmatic,而不在配置文件中以明文形式存储它。
|
||||
|
||||
如何使用 Borgmatic 备份数据库有其[单独的文档页面](https://torsion.org/borgmatic/docs/how-to/backup-your-databases/),你应当在备份前查看一下。对于使用 SQLite 的 GoToSocial,Borgmatic 的简单 `config.yaml` 如下:
|
||||
|
@ -182,11 +182,11 @@ hooks:
|
|||
|
||||
您需要将该文件放在您的 GoToSocial 实例上,并确保该文件是可执行的。它需要 Python 3,安装 Borg 和 Borgmatic 后您应该已经具备。它仅依赖于 Python 标准库。
|
||||
|
||||
!!! note
|
||||
!!! note "注意"
|
||||
为了确保可靠运行,您应确保 GoToSocial 配置中的 [storage-local-base-path](../configuration/storage.md) 使用的是绝对路径。否则您将需要自己调整路径。
|
||||
|
||||
```sh
|
||||
$ gotosocial admin media list-attachments --local-only | \
|
||||
$ gotosocial --config-path /path/to/config.yaml admin media list-attachments --local-only | \
|
||||
/path/to/media-to-borg-patterns.py \
|
||||
<storage-local-base-path>
|
||||
```
|
||||
|
@ -199,7 +199,7 @@ R <storage-local-base-path>
|
|||
- <storage-local-base-path>/*
|
||||
```
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
你可以通过向 `media-to-borg-patterns.py` 传递 `--help` 来查看帮助。通过将文件位置作为脚本的最后一个参数,也可以将输出直接写入文件。
|
||||
|
||||
给定这组模式,Borg 将从 `<storage-local-base-path>` 开始寻找文件。任何匹配路径前缀 `pp:` 的都会被包括进去。其他的则会匹配最后一个模式,从存档中排除。
|
||||
|
@ -211,7 +211,7 @@ R <storage-local-base-path>
|
|||
|
||||
```ini
|
||||
[Service]
|
||||
ExecStartPre=/path/to/gotosocial admin media list-attachments --local-only | /path/to/media-to-borg-patterns.py <storage-local-base-path> /etc/borgmatic/gotosocial_patterns
|
||||
ExecStartPre=/path/to/gotosocial --config-path /path/to/config.yaml admin media list-attachments --local-only | /path/to/media-to-borg-patterns.py <storage-local-base-path> /etc/borgmatic/gotosocial_patterns
|
||||
```
|
||||
|
||||
建议查看的文档:
|
||||
|
|
|
@ -27,13 +27,13 @@ GoToSocial - 一个联邦制社交媒体服务器
|
|||
|
||||
在 `可用命令` 下,可以看到标准的 `server` 命令。但是也有处理管理和调试的命令,这些将在本文档中进行解释。
|
||||
|
||||
!!! Info "将全局配置传递给 CLI"
|
||||
!!! info "将全局配置传递给 CLI"
|
||||
|
||||
对于所有这些命令,你仍然需要正确设置全局选项,以便 CLI 工具知道如何连接到你的数据库,以及使用哪个数据库、哪个主机和账户域等。
|
||||
|
||||
你可以使用环境变量设置这些选项,通过 CLI 标志传递它们(例如,`gotosocial [commands] --host example.org`),或者只需将 CLI 工具指向你的配置文件(例如,`gotosocial --config-path ./config.yaml [commands]`)。
|
||||
|
||||
!!! Info
|
||||
!!! info "附注"
|
||||
|
||||
运行 CLI 命令时,你将会看到如下输出:
|
||||
|
||||
|
@ -45,7 +45,7 @@ GoToSocial - 一个联邦制社交媒体服务器
|
|||
|
||||
这是正常的,表示命令已按预期运行。
|
||||
|
||||
!!! Warning "运行管理命令后重启 GtS"
|
||||
!!! warning "运行管理命令后重启 GtS"
|
||||
|
||||
由于 GoToSocial 的内部缓存机制,你可能需要在运行某些命令后重启 GoToSocial,以使命令的效果“生效”。我们仍在寻找一种无需重启的方法。在此期间,需要在运行命令后重启的命令将在下文中突出显示。
|
||||
|
||||
|
@ -86,7 +86,7 @@ gotosocial admin account create \
|
|||
|
||||
此命令可用于确认你的实例上的用户+账户,允许他们登录并使用账户。
|
||||
|
||||
!!! Info
|
||||
!!! info "附注"
|
||||
|
||||
如果账户是使用 `admin account create` 创建的,则不必在账户上运行 `confirm`,它将已被确认。
|
||||
|
||||
|
@ -113,7 +113,7 @@ gotosocial admin account confirm --username some_username --config-path config.y
|
|||
|
||||
此命令可用于将用户提升为管理员。
|
||||
|
||||
!!! Warning "需要重启服务器"
|
||||
!!! warning "需要重启服务器"
|
||||
|
||||
为使更改生效,此命令需要在运行命令后重启 GoToSocial。
|
||||
|
||||
|
@ -140,7 +140,7 @@ gotosocial admin account promote --username some_username --config-path config.y
|
|||
|
||||
此命令可用于将用户从管理员降级为普通用户。
|
||||
|
||||
!!! Warning "需要重启服务器"
|
||||
!!! warning "需要重启服务器"
|
||||
|
||||
为使更改生效,此命令需要在运行命令后重启 GoToSocial。
|
||||
|
||||
|
@ -167,7 +167,7 @@ gotosocial admin account demote --username some_username --config-path config.ya
|
|||
|
||||
此命令可用于在你的实例上禁用一个账户:禁止其登录或执行任何操作,但不删除数据。
|
||||
|
||||
!!! Warning "需要重启服务器"
|
||||
!!! warning "需要重启服务器"
|
||||
|
||||
为使更改生效,此命令需要在运行命令后重启 GoToSocial。
|
||||
|
||||
|
@ -194,7 +194,7 @@ gotosocial admin account disable --username some_username --config-path config.y
|
|||
|
||||
此命令可用于重新启用你实例上的账户,撤销之前的 `disable` 命令。
|
||||
|
||||
!!! Warning "需要重启服务器"
|
||||
!!! warning "需要重启服务器"
|
||||
|
||||
为使更改生效,此命令需要在运行命令后重启 GoToSocial。
|
||||
|
||||
|
@ -221,7 +221,7 @@ gotosocial admin account enable --username some_username --config-path config.ya
|
|||
|
||||
此命令可用于为指定的本站账户设置新密码。
|
||||
|
||||
!!! Warning "需要重启服务器"
|
||||
!!! warning "需要重启服务器"
|
||||
|
||||
为使更改生效,此命令需要在运行命令后重启 GoToSocial。
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
无论你选择使用 SQLite 还是 Postgres 来运行 GoToSocial,可能都需要偶尔执行一些维护工作,以保持数据库的良好运作。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
|
||||
尽管此处提供的维护建议旨在不破坏现有数据,你还是应该在手动执行维护操作之前备份数据库。这样,如果输入错误或意外运行了不当命令,可以恢复备份并重试。
|
||||
|
||||
!!! danger
|
||||
!!! danger "危险"
|
||||
|
||||
**强烈不建议**手动创建、删除或更新 GoToSocial 数据库中的条目,这里不会提供相关命令。即使你认为自己知道在做什么,运行 `DELETE` 等语句可能会引入非常难以排查的问题。以下维护建议旨在帮助你的实例平稳运行;如果你手动进入数据库并对条目、表和索引进行修改,它们不会拯救你的数据。
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
GoToSocial 支持屏蔽/封禁那些你不想与你的实例联合的域名。在我们的文档中,“屏蔽”和“封禁”这两个术语在涉及域名时可以互换使用,因为它们的意思相同:屏蔽你的实例与目标域名上的实例相互通信,有效地切断两个实例之间的联合。
|
||||
|
||||
你可以使用[实例管理面板](./settings.md#联合)查看、创建和移除域名屏蔽和域名允许。
|
||||
你可以使用[实例管理面板](./settings.md#域名权限)查看、创建和移除域名屏蔽和域名允许。
|
||||
|
||||
本文档重点说明域名屏蔽实际*作用*是什么,以及创建新域名屏蔽时会产生哪些副作用。
|
||||
|
||||
|
@ -54,7 +54,7 @@ GoToSocial 支持屏蔽/封禁那些你不想与你的实例联合的域名。
|
|||
3. 删除封禁帐户的所有贴文。
|
||||
4. 删除封禁帐户及其贴文的所有媒体,包括媒体附件、头像、头图和表情符号。
|
||||
|
||||
!!! danger
|
||||
!!! danger "危险"
|
||||
目前,上述大多数副作用是**不可逆**的。如果你在屏蔽后取消屏蔽一个域名,该域名上的所有帐户将不再被标记为已封禁,并且你将能够再次与他们互动,但所有关系仍将被清除,所有贴文和媒体将被删除。
|
||||
|
||||
在屏蔽一个域名之前请仔细考虑。
|
||||
|
|
145
docs/locales/zh/admin/domain_permission_subscriptions.md
Normal file
145
docs/locales/zh/admin/domain_permission_subscriptions.md
Normal file
|
@ -0,0 +1,145 @@
|
|||
# 域名权限订阅
|
||||
|
||||
你可以通过[管理设置面板](./settings.md#订阅)创建和管理域名权限订阅。
|
||||
|
||||
域名权限订阅允许你指定一个域名权限列表托管的URL。默认情况下,每24小时在当前时区晚上11点进行自动更新,你的实例将获取并解析你订阅的每个列表,基于在列表中发现的条目,按照优先级(从高到低)顺序创建域(或域名权限草稿)。
|
||||
|
||||
每个域名权限订阅可以用来创建域名允许或域名阻止条目。
|
||||
|
||||
!!! warning "警告"
|
||||
目前,通过阻止列表订阅只能创建“屏蔽”级别的域名阻止条目;其他严重程度尚不支持。订阅阻止列表中严重程度为“隐藏”或“限制”等的条目将被跳过。
|
||||
|
||||
## 优先级
|
||||
|
||||
当存在多个域名权限订阅时,它们将按照优先级顺序(从最高优先级(255)到最低优先级(0))被获取和解析。
|
||||
|
||||
在优先级较高的列表上发现的权限条目将覆盖优先级较低的列表上的权限条目。
|
||||
|
||||
例如,一名实例管理员订阅了两个允许列表,“重要列表”优先级为255,“不太重要的列表”优先级为128。每个订阅列表都包含了`good-eggs.example.org`的条目。
|
||||
|
||||
那么优先级较高的订阅会负责创建和管理`good-eggs.example.org`的域名允许条目。
|
||||
|
||||
如果移除了优先级较高的订阅,那么下次获取所有订阅时,“不太重要的列表”将创建(或接管)该域名允许条目。
|
||||
|
||||
## 孤立权限
|
||||
|
||||
目前没有被域名权限订阅管理的域名权限条目(阻止条目和允许条目)被认为是“孤立”权限。这包括管理员手动在设置面板中创建的权限,或者是通过导入/导出页面手动导入的权限。
|
||||
|
||||
如果你愿意,在创建域名权限订阅时,可以将该订阅的[“接管孤立权限条目”](./settings.md#接管孤立权限条目)设置为 true。如果一个启用了“接管孤立权限条目”的域名权限订阅遇到一个孤立权限,并且该条目 *也在该订阅地址指向的列表中*,那么它将把该孤立条目的订阅ID设置为其自身ID,来“接收”此孤立条目。
|
||||
|
||||
例如,一个实例管理员手动为域名`horrid-trolls.example.org`创建了域名阻止条目。稍后,他们创建了一个域名阻止列表订阅,并将“收养孤儿”设置为真,且该订阅包含`horrid-trolls.example.org`。当实例获取并解析列表,并从中创建域名权限条目时,`horrid-trolls.example.org`这个孤立的域名阻止条目将被刚刚配置的域名权限订阅接收。现在,如果域名权限订阅被移除,且在移除时勾选了移除订阅所拥有的所有权限选项,那么`horrid-trolls.example.org`这个域名阻止条目也将被移除。
|
||||
|
||||
## 域名权限订阅的几种有趣的应用场景
|
||||
|
||||
### 1. 创建白名单联合实例集群
|
||||
|
||||
域名权限订阅使得创建白名单联合实例集群集群变得更加容易,也就是说,一组实例理论上可以形成自己的迷你联邦宇宙,每个实例在[白名单联合模式](./federation_modes.md#白名单联合模式)下运行,并订阅同一个合作管理的、托管在某处的允许列表。
|
||||
|
||||
例如,实例 `instance-a.example.org`、`instance-b.example.org` 和 `instance-c.example.org` 决定他们只想彼此联合。
|
||||
|
||||
他们可以使用像 GitHub 这样的版本管理平台托管一个纯文本格式的允许列表,比如在 `https://raw.githubusercontent.com/our-cluster/allowlist/refs/heads/main/allows.txt`。
|
||||
|
||||
纯文本格式的允许列表内容如下:
|
||||
|
||||
```text
|
||||
instance-a.example.org
|
||||
instance-b.example.org
|
||||
instance-c.example.org
|
||||
```
|
||||
|
||||
每个实例管理员都将他们的联合模式设置为`白名单`,并创建一个类型为“允许”,订阅地址为 `https://raw.githubusercontent.com/our-cluster/allowlist/refs/heads/main/allows.txt` 的订阅,这会为他们自己的域名以及集群中的其他域名创建域名允许条目。
|
||||
|
||||
在某个时候,来自 `instance-d.example.org` 的某人(在站外)申请被添加到集群中。现有的管理员同意,并更新他们的纯文本格式允许列表为:
|
||||
|
||||
```text
|
||||
instance-a.example.org
|
||||
instance-b.example.org
|
||||
instance-c.example.org
|
||||
instance-d.example.org
|
||||
```
|
||||
|
||||
下次每个实例获取列表时,将为 `instance-d.example.org` 创建一个新的域名允许条目,它将能够与该列表中的其他域进行联合。
|
||||
|
||||
### 2. 合作管理阻止列表
|
||||
|
||||
域名权限订阅使得合作管理和订阅共享的、包含非法/极右/其他不良账户和内容的域名的阻止列表变得容易。
|
||||
|
||||
例如,实例 `instance-e.example.org`、`instance-f.example.org` 和 `instance-g.example.org` 的管理员认定:他们厌倦了通过与坏人玩打地鼠游戏来重复工作。为了让生活更轻松,他们决定合作开发一个共享的阻止列表。
|
||||
|
||||
他们使用像 GitHub 这样的版本管理平台在类似 `https://raw.githubusercontent.com/baddies/blocklist/refs/heads/main/blocks.csv` 的地方托管一个阻止列表。
|
||||
|
||||
当有人发现另一个他们不喜欢的实例时,他们可以通过合并请求或类似方法添加这个有问题的实例到域名列表中。
|
||||
|
||||
例如,有人从一个新实例 `fashy-arseholes.example.org` 收到一个不愉快的回复。他们使用他们的协作工具,建议将 `fashy-arseholes.example.org` 添加到阻止列表。经过一些审议和讨论后,该域被添加到列表中。
|
||||
|
||||
下次 `instance-e.example.org`、`instance-f.example.org` 和 `instance-g.example.org` 获取阻止列表时,将为 `fashy-arseholes.example.org` 创建一个阻止条目。
|
||||
|
||||
### 3. 订阅阻止列表,但忽略其中的一部分
|
||||
|
||||
假设上一节中的 `instance-g.example.org` 认定他们同意大部分协作策划的阻止列表,但出于某种原因,他们实际上希望继续与 `fashy-arseholes.example.org` 联合。
|
||||
|
||||
这可以通过以下三种方法实现:
|
||||
|
||||
1. `instance-g.example.org` 的管理员订阅共享阻止列表,但他们将其["创建为草稿"](./settings.md#将此条目设为草稿)选项设置为 true。当他们的实例获取阻止列表时,会为 `fashy-arseholes.example.org` 创建一个阻止条目草稿。`instance-g` 的管理员只需将权限保留为草稿或拒绝它,因此它永远不会生效。
|
||||
2. 在重新获取阻止列表之前,`instance-g.example.org` 的管理员为 `instance-g.example.org` 创建一个[域名权限例外](./settings.md#例外)条目。设置保存后,域名权限订阅将无法`instance-g.example.org` 域名创建权限,因此在列表下次被获取时,共享阻止列表上对于 `instance-g.example.org` 的阻止不会在 `instance-g.example.org` 的实例数据库中创建。
|
||||
3. `instance-g.example.org` 的管理员在其实例上为 `fashy-arseholes.example.org` 创建一个显式的域名允许条目。`instance-g` 实例在`黑名单`联合模式下运行,因此[显式允许条目将覆盖域名阻止条目](./federation_modes.md#黑名单模式)。`fashy-arseholes` 域名将保持未被阻止的状态。
|
||||
|
||||
### 4. 直接订阅另一个实例的阻止列表
|
||||
|
||||
GoToSocial 能够获取和解析 JSON 格式的域名权限列表,所以可以通过他们的 `/api/v1/instance/domain_blocks` (Mastodon) 或 `/api/v1/instance/peers?filter=suspended` (GoToSocial)端点(如果已公开)直接订阅另一个实例的屏蔽列表。
|
||||
|
||||
例如,Mastodon 实例 `peepee.poopoo.example.org` 公开他们的阻止列表,而GoToSocial实例的所有者 `instance-h.example.org` 认定他们非常喜欢该 Mastodon 管理员的标准。他们创建一个JSON类型的域名权限订阅,并将地址设为 `https://peepee.poopoo.example.org/api/v1/instance/domain_blocks`。他们的实例将每24小时获取一次对方 Mastodon 实例的阻止列表JSON,并根据其中发现的条目创建权限。
|
||||
|
||||
## 域名权限订阅列表的格式示例
|
||||
|
||||
以下是 GoToSocial 能够解析的不同权限列表格式的示例。
|
||||
|
||||
每个列表包含三个域,`bumfaces.net`、`peepee.poopoo` 和 `nothanks.com`。
|
||||
|
||||
### CSV
|
||||
|
||||
CSV列表使用内容类型 `text/csv`。
|
||||
|
||||
Mastodon域名权限通常使用这种格式导出。
|
||||
|
||||
```csv
|
||||
#domain,#severity,#reject_media,#reject_reports,#public_comment,#obfuscate
|
||||
bumfaces.net,suspend,false,false,这个实例上有坏蛋,false
|
||||
peepee.poopoo,suspend,false,false,骚扰,false
|
||||
nothanks.com,suspend,false,false,,false
|
||||
```
|
||||
|
||||
### JSON (application/json)
|
||||
|
||||
JSON列表使用内容类型 `application/json`。
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"domain": "bumfaces.net",
|
||||
"suspended_at": "2020-05-13T13:29:12.000Z",
|
||||
"public_comment": "这个实例上有坏蛋"
|
||||
},
|
||||
{
|
||||
"domain": "peepee.poopoo",
|
||||
"suspended_at": "2020-05-13T13:29:12.000Z",
|
||||
"public_comment": "骚扰"
|
||||
},
|
||||
{
|
||||
"domain": "nothanks.com",
|
||||
"suspended_at": "2020-05-13T13:29:12.000Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 纯文本 (text/plain)
|
||||
|
||||
纯文本列表使用内容类型 `text/plain`。
|
||||
|
||||
注意在纯文本列表中无法包含像“obfuscate”或“public comment”这样的字段,因为它们只是一个以换行符分隔的域名列表。
|
||||
|
||||
```text
|
||||
bumfaces.net
|
||||
peepee.poopoo
|
||||
nothanks.com
|
||||
```
|
|
@ -10,12 +10,12 @@ GoToSocial 当前提供“黑名单”和“白名单”联合模式,可以通
|
|||
|
||||
当你的实例遇到它以前未见过的贴文或账户的提及或公告时,如果该资源的域未通过域屏蔽条目被屏蔽,它将会去获取该资源。
|
||||
|
||||
!!! info
|
||||
!!! info "附注"
|
||||
黑名单联合模式是 GoToSocial 的默认联合模式。它也是大多数其他 ActivityPub 服务器实现的默认联合模式。
|
||||
|
||||
## 白名单联合模式
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
白名单联合模式仍然被认为是“实验性”的,我们正在研究其在实际中的表现。它应该如其名称所示,但可能会在其他地方导致错误或出现边缘情况,我们还不确定!
|
||||
|
||||
当 `instance-federation-mode` 设置为 `allowlist` 时,你的实例将仅与通过设置面板明确设为允许的实例联合,并限制任何未被允许的实例的访问。
|
||||
|
@ -24,7 +24,7 @@ GoToSocial 当前提供“黑名单”和“白名单”联合模式,可以通
|
|||
|
||||
当你的实例遇到它以前未见过的贴文或账户的提及或公告时,它只会在资源所属域名被明确允许时才去获取资源。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
白名单联合模式在你希望仅与选择的“可信”实例联合的情况下非常有用。然而,这会影响发现过程。在黑名单联合模式下,你会通过转发和回复自然地遇到未知实例的贴文和账户,但在白名单联合模式下,这样的偶然发现不会发生。
|
||||
|
||||
因此,建议你要么先从黑名单联合模式开始,然后在确定喜欢哪些其他实例后切换到白名单联合模式,要么从白名单联合模式开始,并在首次启动实例后准备好并导入白名单,以便“启动”它。
|
||||
|
@ -54,7 +54,7 @@ GoToSocial 当前提供“黑名单”和“白名单”联合模式,可以通
|
|||
|
||||
如果上述任何条件不满足,请求将被拒绝。
|
||||
|
||||
!!! danger
|
||||
!!! danger "危险"
|
||||
结合屏蔽和允许是一项棘手的工作!
|
||||
|
||||
在导入允许和黑名单时,你应该始终手动审核列表,以确保不会无意中屏蔽你不想屏蔽的实例,因为这可能会有**非常烦人的副作用**,例如移除关注/被关注、贴文等。
|
||||
|
|
|
@ -47,11 +47,11 @@ GoToSocial 提供了三个变量,让你(管理员)可以调节何时以及
|
|||
|
||||
上述设置意味着从午夜开始每8小时,GoToSocial 将清除任何缓存超过1天(24小时)的媒体。清理任务将在 00:00、08:00 和 16:00,即午夜、上午8点和下午4点运行。使用此配置,你可能将外站媒体在存储中保留的最长时间约为32小时。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
将 `media-remote-cache-days` 设置为0或更小意味着外站媒体将永不被清除。然而,本站孤立媒体的清理任务和其他一致性检查仍将按其他变量定义的计划运行。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
如果你愿意,你也可以通过管理面板手动执行一次性清理操作([查看文档](./settings.md#媒体))。
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
将 `media-cleanup-every` 设置为非常小的值,如 `"30m"` 或更小,可能会导致你的实例不断遍历附件,导致数据使用率高而效益甚微。我们不建议将该值设置为小于约 `"8h"`,即便如此,可能也显得过度。
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
GoToSocial 当前提供“屏蔽”、“允许”和禁用的 HTTP 请求头过滤模式,可以通过在 config.yaml 中设置 `advanced-header-filter-mode`,或使用环境变量 `GTS_ADVANCED_HEADER_FILTER_MODE` 来配置。这些模式的具体说明如下。
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
HTTP 请求头过滤是一个进阶设置。如果你不熟悉 HTTP 请求头的使用和复杂性,修改这些设置可能会导致联合功能中断,甚至无法访问你自己的实例。
|
||||
|
||||
HTTP 请求头过滤仍被视为“实验性”功能。它应该能如预期工作,但可能会导致其他地方出现错误或边缘情况,这点我们尚不确定!
|
||||
|
@ -27,5 +27,5 @@ GoToSocial 当前提供“屏蔽”、“允许”和禁用的 HTTP 请求头过
|
|||
|
||||
在允许模式下,请求只有在被明确允许且未被明确屏蔽的情况下才会被接受。
|
||||
|
||||
!!! danger
|
||||
!!! danger "危险"
|
||||
允许过滤模式是一个极为严格的模式,几乎肯定会阻止许多(合法的)客户端访问你的实例,包括你自己。只有在完全明确你的目标时才应启用此模式。
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
GoToSocial 在主域名上提供一个 `robots.txt` 文件。该文件包含试图屏蔽已知 AI 爬虫的一些规则,以及其他一些索引器。它还包括一些规则,以确保诸如 API 端点之类的内容不会被搜索引擎索引,因为这些内容没有被索引的必要。
|
||||
|
||||
## 允许/禁止统计数据收集
|
||||
|
||||
你可以通过修改配置 `instance-stats-mode` 来允许或禁止爬虫从 `/nodeinfo/2.0` 和 `/nodeinfo/2.1` 端点收集你的实例的统计数据,此设置会修改 `robots.txt` 文件。更多详情请参见 [实例配置](../configuration/instance.md)。
|
||||
|
||||
## AI 爬虫
|
||||
|
||||
AI 爬虫来自一个[社区维护的仓库][airobots]。目前是手动保持同步的。如果你知道有任何遗漏的爬虫,请给他们提交一个 PR!
|
||||
|
|
|
@ -34,11 +34,11 @@ GoToSocial 管理设置面板使用 [管理 API](https://docs.gotosocial.org/zh-
|
|||
|
||||
你可以使用此部分搜索账户并对其执行管理操作。
|
||||
|
||||
### 联合
|
||||
### 域名权限
|
||||
|
||||

|
||||
|
||||
在联合部分,你可以创建、删除和审核明确的域名屏蔽和域名允许。
|
||||
在域名权限部分,你可以创建、删除和查看域名阻止条目、域名允许条目、草稿、排除项和订阅。
|
||||
|
||||
关于联合设置的更多详细信息,特别是域名允许和域名屏蔽如何结合使用,请参阅 [联合模式部分](./federation_modes.md) 和 [域名屏蔽部分](./domain_blocks.md)。
|
||||
|
||||
|
@ -46,20 +46,99 @@ GoToSocial 管理设置面板使用 [管理 API](https://docs.gotosocial.org/zh-
|
|||
|
||||
你可以在搜索字段中输入一个要封禁的域名,这将过滤列表以显示你是否已有该域名的屏蔽条目。
|
||||
|
||||
点击“封禁”会显示一个表单,允许你添加公开和/或私人评论,并提交以添加屏蔽。添加封禁后,该实例上的所有已知账户将被封禁,并阻止与该被屏蔽实例上的任何用户的新互动。
|
||||
点击“封禁”会显示一个表单,允许你添加公开和/或私人评论,并提交以添加屏蔽。
|
||||
|
||||
添加封禁后,该实例上的所有已知账户将被封禁,并阻止与该被屏蔽实例上的任何用户的新互动。
|
||||
|
||||
#### 域名允许
|
||||
|
||||
域名允许部分的工作方式与域名屏蔽部分类似,只是用于明确的域名允许而不是域名屏蔽。
|
||||
|
||||
#### 批量导入/导出
|
||||
#### 导入/导出
|
||||
|
||||
通过联合部分底部的链接(或访问 `/settings/admin/federation/import-export`),你可以批量导入/导出屏蔽列表和允许列表。
|
||||
你可以在这一部分批量导入/导出JSON、CSV或纯文本格式的域名权限条目。
|
||||
|
||||

|
||||
|
||||
通过输入字段或文件导入列表后,你可以在导入子集之前查看列表中的条目。你还会在使用子域的条目中收到警告,此处还提供一种轻松将其更改为主域的方法。
|
||||
|
||||
#### 草稿
|
||||
|
||||
在这一部分,你可以创建、搜索、接受和拒绝域名权限草稿。
|
||||
|
||||
域名权限草稿是已被提议,但尚未生效的域域名权限条目(可以手动创建或从已订阅的阻止/允许列表中添加)。
|
||||
|
||||
在接受前,域名权限草稿将对目标域名的联合没有任何影响。一旦被接受,它将被转换为域名阻止条目或域名允许条目,并开始执行。
|
||||
|
||||
#### 例外
|
||||
|
||||
在这一部分,您可以创建、搜索和移除域名权限例外条目。
|
||||
|
||||
域名权限例外可以防止某域名(及其所有子域)的权限被域名权限订阅自动管理。
|
||||
|
||||
例如,如果你为域名 `example.org` 创建例外条目,那么在创建域名权限草稿和域名阻止/允许条目时,阻止列表或允许列表订阅将排除 `example.org` 及其任何子域(如 `sub.example.org`,`another.sub.example.org` 等)的条目。
|
||||
|
||||
此功能可以让你在明确知道是否要与某个域名进行联合的情况下,手动管理被设为例外的域名的权限,不受域名权限订阅中包含的条目的影响。
|
||||
|
||||
请注意,仅针对某个域名创建排除条目本身并不会对与该域名的联合产生影响,它只有与权限订阅结合使用时才会发挥作用。
|
||||
|
||||
#### 订阅
|
||||
|
||||
在这一部分,你可以创建、搜索、编辑、测试和移除域名权限订阅。
|
||||
|
||||
域名权限订阅允许您指定权限列表的托管地址。默认情况下,每天晚上11点,你的实例将获取并解析订阅的每个列表,并根据列表中的条目创建域名权限(或域名权限草稿)。
|
||||
|
||||
##### 标题
|
||||
|
||||
您可以选择使用标题字段为订阅设置标题,以便对自己和其他管理员进行提醒。
|
||||
|
||||
例如,您可能会订阅 `https://lists.example.org/baddies.csv` 上的列表,并将该订阅的标题设置为某些反映该列表内容的描述,如“基础阻止列表(最为恶劣的实例)”或类似描述。
|
||||
|
||||
##### 订阅优先级
|
||||
|
||||
当你指定了多个域名权限订阅时,它们将按优先级顺序从最高优先级 (255) 到最低优先级 (0) 被获取和解析。
|
||||
|
||||
在优先级排名靠前的列表中发现的权限将覆盖在优先级排名靠后的列表中的权限。
|
||||
|
||||
有关优先级的更多信息,参见单独的[域名权限订阅](./domain_permission_subscriptions.md)文档。
|
||||
|
||||
##### 权限类型
|
||||
|
||||
你可以使用此下拉菜单选择为在订阅地址中发现的权限创建的条目类型,可以为阻止或允许。
|
||||
|
||||
##### 内容类型
|
||||
|
||||
您可以使用此下拉菜单选择订阅地址指向的列表的内容类型。
|
||||
|
||||
要订阅与 Mastodon 格式兼容的权限列表,可以选择 CSV,要使用纯文本域名列表,可以选择 plain,也可以选择 JSON,用于订阅以 JSON 格式导出的列表。
|
||||
|
||||
##### 基础认证(Basic Auth)
|
||||
|
||||
勾选此复选框,可以为订阅列表提供基础认证用户名和/或密码凭证,这些凭证将在每次向订阅地址请求列表时一并发送。
|
||||
|
||||
##### 接管孤立权限条目
|
||||
|
||||
如果勾选此框,那么在以下情况下,任何现有的域名权限将由该订阅管理:
|
||||
|
||||
1. 该权限条目没有关联的订阅 ID(即,它们不受任何域权限订阅管理)。
|
||||
2. 该权限条目与此订阅地址中包含的域名权限匹配。
|
||||
|
||||
有关孤立权限的更多信息,参见单独的[域名权限订阅](./domain_permission_subscriptions.md)文档。
|
||||
|
||||
##### 将此条目设为草稿
|
||||
|
||||
勾选此复选框后(该复选框默认勾选),通过此订阅创建的任何权限条目将以**草稿**类型创建,需要手动批准才能生效。
|
||||
|
||||
建议保留此复选框为已勾选状态,除非您完全信任订阅列表,以避免无意中阻止或允许您不想阻止或允许的域。
|
||||
|
||||
##### 测试订阅
|
||||
|
||||
要测试订阅是否可以被成功解析,首先创建订阅,然后在该订阅的详情视图中,点击“测试”按钮。
|
||||
|
||||
如果您的实例能够获取并解析订阅地址处的权限列表,则在点击“测试”后您将看到这些权限的列表。否则,您将看到一条错误信息。
|
||||
|
||||

|
||||
|
||||
## 管理
|
||||
|
||||
实例管理设置。
|
||||
|
@ -167,3 +246,11 @@ GoToSocial 管理设置面板使用 [管理 API](https://docs.gotosocial.org/zh-
|
|||
选择的 **联系人用户** 必须是实例上的活跃(未封禁)的管理员和/或站务。
|
||||
|
||||
如果你是在单用户实例上并将管理员权限授予你的主账户,你只需在此处填写自己的用户名即可;无需为此专门创建管理账户。
|
||||
|
||||
### 实例自定义 CSS
|
||||
|
||||
自定义 CSS 允许您进一步调整通过浏览器访问的实例时的外观。
|
||||
|
||||
这些自定义 CSS 将应用于实例的所有页面。但用户主题和 CSS 仍优先于此处的自定义设置。
|
||||
|
||||
有关为您的实例编写自定义 CSS 的一些技巧,请参阅[自定义 CSS](../user_guide/custom_css.md)页面。
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
注意,作为实例管理员,无论你是否愿意,你都需对在你的实例上发布的内容负责。如果你的实例用户在联合网上骚扰或烦扰他人,可能会导致你的实例名誉受损,并被其他人屏蔽。妥善管理一个社区需要付出努力。因此,你应仔细考虑是否愿意且有能力进行管理,及是否只接受朋友和你非常信任的人注册账户。
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
为使注册流程正常运作,你的实例应[配置电子邮件发件服务](../configuration/smtp.md)。
|
||||
|
||||
如下所述,在注册流程中,会向你(作为管理员/站务)和申请人发送几封邮件,包括要求对方确认邮箱地址的邮件。
|
||||
|
@ -41,7 +41,7 @@
|
|||
|
||||
如果你**拒绝**注册,可以选择通知申请人注册被拒,你可以通过勾选“发送邮件”复选框来实现。这将向申请人发送一封简短邮件,告知其被拒。如果需要,还可以添加自定义消息,该消息将添加在邮件底部。你还可以添加仅供其他管理员查看的私人备注。
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
你可能希望等申请人确认他们的电子邮件地址后再批准注册,以防申请时输入错误或提供不是他们的电子邮件地址。如果他们不能确认电子邮件地址,将无法登录和使用账户。
|
||||
|
||||
## 注册限制
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
|
||||
被认为是骚扰信息的消息将不会存储在你的本站实例上,也不会生成通知。
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
骚扰信息过滤器必然是不完美的工具,因为它们可能会误判一些合法的信息为垃圾,或者确实未能抓住一些*确实*是垃圾的信息。
|
||||
|
||||
启用 `instance-federation-spam-filter` 应被视为当联合网络遭遇骚扰信息攻击时的一种“加固”选项。在正常情况下,你可能希望将其关闭,以避免意外过滤掉合法信息。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
如果你想检查骚扰信息过滤器捕获了哪些内容(如果有的话),可以在日志中搜索 `looked like spam`。
|
||||
|
||||
如果你[将 GoToSocial 作为 systemd 服务运行](../getting_started/installation/metal.md#optional-enable-the-systemd-service),可以使用以下命令:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
本节涵盖了多种缓存技术,这些技术可以提高 GoToSocial 在高流量情况下的稳定性,并减轻 GoToSocial 实例的一部分工作负担。
|
||||
|
||||
!!! note
|
||||
!!! note "注意"
|
||||
这些指南仅在你运行[反向代理](../../getting_started/reverse_proxy/index.md)时才有意义。
|
||||
|
||||
## 指南
|
||||
|
|
|
@ -66,7 +66,7 @@ tls-certificate-key: "/path/to/private.key"
|
|||
|
||||
这将禁用通过 Lets Encrypt 内置的证书配置,并指示 GoToSocial 在磁盘上找到证书。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
在续订证书后应重启 GoToSocial。它在这种情况下不会自动监测证书的更换。
|
||||
|
||||
### 使用反向代理
|
||||
|
@ -93,7 +93,7 @@ tls-certificate-key: ""
|
|||
* [Traefik](https://doc.traefik.io/traefik/https/tls/)
|
||||
* [Caddy](https://caddyserver.com/docs/caddyfile/directives/tls)
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
在你的反向代理中配置 TLS 时,请确保你配置了一组较现代的兼容版本和加密套件。可以使用 [Mozilla SSL Configuration Generator](https://ssl-config.mozilla.org/) 的“中级”配置。
|
||||
|
||||
检查你的反向代理文档,以了解在证书更改后是否需要重新加载或重启它。并非所有的反向代理都会自动检测到这一点。
|
||||
|
|
|
@ -23,12 +23,12 @@ healthcheck:
|
|||
|
||||
上述健康检查将在 30 秒后开始,每两分钟检查一次服务是否可用,通过对 `/readyz` 进行 HEAD 请求。如果检查连续失败五次,服务将被标记为不健康。你可以在使用的编排系统中利用此功能强制重启容器。
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
在慢速硬件上进行数据库迁移时,迁移可能会超过上述健康检查所允许的 10 分钟。
|
||||
|
||||
在这样的系统上,你可能需要增加健康检查的间隔或重试次数,以确保不会在迁移中途停止 GoToSocial(这会很糟糕!)。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
尽管健康检查端点不透露任何敏感信息,并且只运行非常简单的查询,你可能希望避免将它们暴露给外部世界。你可以在 nginx 中通过在 `server` 段中添加以下代码片段来实现:
|
||||
|
||||
```nginx
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
本指南解释了如何使用 `@me@example.org` 这样的用户名,但将 GoToSocial 实例本身运行在例如 `social.example.org` 这样的子域名的方法。这种部署布局的配置**必须**在第一次启动 GoToSocial 前完成。
|
||||
|
||||
!!! danger
|
||||
!!! danger "警告"
|
||||
一旦与他人联合后就无法更改域名布局。服务器会因此产生混淆,而你需要说服每个与你联合的实例管理员修改其数据库来解决问题。同时,你还需要在本地重新生成数据库,创建一个新的实例账户和加密密钥对。
|
||||
|
||||
## 背景
|
||||
|
@ -49,7 +49,7 @@ host: social.example.org
|
|||
account-domain: example.org
|
||||
```
|
||||
|
||||
!!! info
|
||||
!!! info "附注"
|
||||
`host` 必须始终是运行 GoToSocial 实例的 DNS 名称。它不影响 GoToSocial 实例绑定的 IP 地址。该地址由 `bind-address` 控制。
|
||||
|
||||
## 反向代理
|
||||
|
@ -62,7 +62,7 @@ account-domain: example.org
|
|||
* `/.well-known/host-meta`
|
||||
* `/.well-known/nodeinfo`
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
不要将 API 端点 `/api/...` 的请求从账户域代理或重定向到主机域。这会混淆某些客户端用来检测分域部署的启发式方法,导致登录流程中断及其他异常行为。
|
||||
|
||||
### nginx
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
这些指南涵盖如何提高你的 GoToSocial 部署的安全状况。它们不涉及调整 GoToSocial 的设置,而是指出一些你可以做的额外措施,以更好地保护你的实例。
|
||||
|
||||
!!! note
|
||||
!!! note "注意"
|
||||
这些指南中的任何内容旨在增强你的 GoToSocial 部署的安全性;它们不能替代良好的安全实践,比如保持你的系统定期得到修补和更新。
|
||||
|
||||
## 指南
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
SQLite 的运行模式假定数据库和使用它的进程或应用程序位于同一主机上。在运行 WAL 模式(GoToSocial 的默认模式)时,它依赖于进程之间的共享内存来确保数据库完整性。
|
||||
|
||||
!!! quote
|
||||
!!! quote "参考"
|
||||
所有使用数据库的进程必须在同一台主机计算机上;WAL 不能在网络文件系统上工作。这是因为 WAL 需要所有进程共享少量内存,而在不同主机上的进程显然不能相互共享内存。
|
||||
|
||||
— SQLite.org [写前日志](https://www.sqlite.org/wal.html)
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
```bash
|
||||
curl \
|
||||
-X POST \
|
||||
-H 'Content-Type:application/json' \
|
||||
-d '{
|
||||
"client_name": "your_app_name",
|
||||
|
@ -26,7 +25,7 @@ curl \
|
|||
- `write`
|
||||
- `admin`
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
GoToSocial 目前不支持范围授权令牌,因此在此过程中获得的任何令牌都可以代表你执行所有操作,包括如果你的账户具有管理员权限时的管理员操作。然而,始终以最低权限授予你的应用是一个好习惯。例如,如果你的应用不会发布贴文,请使用 scope=read。
|
||||
|
||||
本着这种精神,上述示例使用了`read`,这意味着当未来支持范围令牌时,应用将仅限于执行`read`操作。
|
||||
|
@ -45,7 +44,7 @@ curl \
|
|||
}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
确保将 `client_id` 和 `client_secret` 的值保存到某个位置,以便在需要时参考。
|
||||
|
||||
## 授权你的应用代表你操作
|
||||
|
@ -58,7 +57,7 @@ curl \
|
|||
https://example.org/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=read
|
||||
```
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
如果你在注册应用时使用了不同的范围,在上面的 URL 中将 `scope=read` 替换为你注册时使用的加号分隔的范围列表。例如,如果你注册你的应用时使用了 `scopes` 值 `read write`,那么你应该将上面的 `scope=read` 改为 `scope=read+write`。
|
||||
|
||||
将 URL 粘贴到浏览器后,你会被引导到实例的登录表单,提示你输入邮箱地址和密码以将应用连接到你的账户。
|
||||
|
@ -89,7 +88,6 @@ YOUR_AUTHORIZATION_TOKEN
|
|||
|
||||
```bash
|
||||
curl \
|
||||
-X POST \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
|
||||
|
|
|
@ -24,11 +24,11 @@
|
|||
|
||||
### 我总是超出速率限制!为什么?
|
||||
|
||||
如果你发现自己的速率限制在正常使用时经常被超出(对于你自己和其他请求者也是如此),这可能是因为 GoToSocial 无法通过 IP 地址区分客户端。你可以通过查看实例的日志来调查这个问题。如果(几乎)所有记录的 IP 地址似乎都是相同的 IP 地址(类似于 `172.x.x.x`),那么速率限制将导致问题。
|
||||
如果你发现自己的速率限制在正常使用时经常被超出(对于你自己和其他请求者也是如此),这可能是因为 GoToSocial 无法通过 IP 地址区分客户端。你可以通过查看实例的日志来调查这个问题。如果(几乎)所有记录的客户端 IP 地址似乎都是相同的 IP 地址(类似于 `172.x.x.x`),那么速率限制将导致问题。
|
||||
|
||||
这种情况通常发生在你的服务器运行在 NAT(端口转发)中,或者在没有正确配置的 HTTP 代理之后,导致你的实例将所有传入 IP 地址视为相同的地址:即你的反向代理或网关的 IP 地址。这意味着所有传入请求*共享同一个速率限制*,而不是按 IP 正确分开。
|
||||
|
||||
如果你正在使用 HTTP 代理,那么很可能你的 `trusted-proxies` 未正确配置。如果是这种情况,尝试将反向代理的 IP 地址添加到 `trusted-proxies` 列表中,并重启你的实例。
|
||||
如果你使用了 HTTP 代理,那么你的 `trusted-proxies` 配置可能不正确。详情请参阅 [可信代理](../configuration/trusted_proxies.md) 文档以了解如何解决此问题。
|
||||
|
||||
如果没有使用 HTTP 代理,那么很可能是由 NAT 引起的。在这种情况下,你应该完全禁用速率限制。
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ GoToSocial 使用 [go-swagger](https://github.com/go-swagger/go-swagger) 从代
|
|||
|
||||
大多数 GoToSocial API 端点需要用户级别的 OAuth 令牌。有关如何使用 OAuth 令牌进行 API 认证的指南,请参阅[认证文档](./authentication.md)。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
如果你想更多地使用该规范,还可以直接查看 [swagger.yaml](./swagger.yaml),然后将其粘贴到 [Swagger Editor](https://editor.swagger.io/) 等工具中。这样你可以尝试自动生成不同语言的 GoToSocial API 客户端(不支持,但可以尝试),或者将文档转换为 JSON 或 OpenAPI v3 规范等。更多信息请参见[这里](https://swagger.io/tools/open-source/getting-started/)。
|
||||
|
||||
!!! info "注意事项:上传文件"
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,6 @@
|
|||
# 基础配置
|
||||
|
||||
GoToSocial 的基础配置,包括域名、端口、绑定地址和传输协议等基本内容。
|
||||
|
||||
这里*真正*需要设置的只有 `host`,也就是你实例可以访问的域名,可能还需要设置 `port`。
|
||||
GoToSocial 的顶级配置,包括域名、端口、绑定地址和可信代理等基本信息。
|
||||
|
||||
## 设置
|
||||
|
||||
|
|
|
@ -112,4 +112,47 @@ instance-deliver-to-shared-inboxes: true
|
|||
# 选项: [true, false]
|
||||
# 默认值: false
|
||||
instance-inject-mastodon-version: false
|
||||
|
||||
# 字符串。hh:mm 格式的 24 小时制时间。
|
||||
# 示例: ["14:30", "00:00", "04:00"]
|
||||
# 默认值: "23:00" (晚上11点)。
|
||||
instance-subscriptions-process-from: "23:00"
|
||||
|
||||
|
||||
# 时间间隔。表示更新订阅的周期。
|
||||
# 示例:["24h", "72h", "12h"]
|
||||
# 默认值: "24h"(每天一次)。
|
||||
instance-subscriptions-process-every: "24h"
|
||||
|
||||
# 字符串。允许你自定义是否以及如何在 /api/v1|v2/instance
|
||||
# 和 /nodeinfo 端点向爬虫提供统计数据。
|
||||
#
|
||||
# 请注意,无论你在这里进行何种设置,/api/v1|v2/instance
|
||||
# 端点都不会被 robots.txt 允许抓取,因为这些是客户端
|
||||
# API端点。
|
||||
#
|
||||
# "" / 空字符串(默认模式): 在 instance 和 nodeinfo 端点提供准确的统计数据,
|
||||
# 并在 robots.txt 中禁止爬虫抓取这些端点。这种模式相当于礼貌地
|
||||
# 要求爬虫不抓取,但不能保证它们会遵从这些规则,
|
||||
# 因为遗憾的是,许多爬虫甚至不会检查robots.txt。
|
||||
#
|
||||
# "zero": 在 instance 和 nodeinfo 端点提供全为零的统计数据,
|
||||
# 并在 robots.txt 中禁止爬虫抓取这些端点。
|
||||
# 这种模式阻止行为不端的爬虫收集有关您的实例的统计数据,
|
||||
# 因为所有收集的值都将为0。这(在统计数据方面)
|
||||
# 是保护您的实例隐私的最安全方法。
|
||||
#
|
||||
# "serve": 在 instance 和 nodeinfo 端点提供准确的统计数据,
|
||||
# 并允许爬虫抓取这些端点。如果您希望为
|
||||
# 联邦宇宙统计信息收集项目做贡献,此模式将非常有用。
|
||||
#
|
||||
# "baffle": 在 instance 和 nodeinfo 端点提供随机且荒谬的统计数据,
|
||||
# 并在 robots.txt 中禁止爬虫抓取这些端点。
|
||||
# 这种模式可以用于使不尊重 robots.txt 的爬虫感到困惑。
|
||||
# 警告,此做法可能会引起不尊重 robots.txt 的爬虫开发者的怨恨,
|
||||
# 因此可能会给您的实例带来风险。
|
||||
#
|
||||
# 选项: ["", "zero", "serve", "baffle"]
|
||||
# 默认: ""
|
||||
instance-stats-mode: ""
|
||||
```
|
||||
|
|
|
@ -10,7 +10,7 @@ GoToSocial 支持 [OpenID Connect](https://openid.net/connect/),这是一种
|
|||
- 你希望将用户、账户、密码等的管理委托给外部服务,以简化管理。
|
||||
- 你已经在外部系统中有很多用户,不想在 GoToSocial 中手动重新创建他们。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
如果用户尚不存在,且你的 IdP 没有返回非空的 `email` 作为 claims 的一部分,登录将会失败。这个 email 需要在此实例中是唯一的。尽管我们使用 `sub` claim 将外部身份与 GtS 用户关联,但创建用户时需要一个与之关联的 email。
|
||||
|
||||
## 设置
|
||||
|
|
171
docs/locales/zh/configuration/trusted_proxies.md
Normal file
171
docs/locales/zh/configuration/trusted_proxies.md
Normal file
|
@ -0,0 +1,171 @@
|
|||
# 可信代理
|
||||
|
||||
为了正确执行[速率限制](../api/ratelimiting.md),GoToSocial 依赖于“可信代理”的概念,以准确确定访问你的实例的客户端的 IP 地址。
|
||||
|
||||
“可信代理”是一个中间网络跳转层,GoToSocial 可以配置为信任由该代理层提供的正确的客户端 IP 地址。
|
||||
|
||||
例如,如果你使用 Docker + Nginx 的反向代理配置中运行,那么 Nginx 的 Docker 网络地址应该被配置为可信代理,因为从广域互联网传入的所有流量将通过 Nginx 进入 GoToSocial。
|
||||
|
||||
如果没有正确设置 `trusted-proxies`, GoToSocial 将看到所有的入站客户端的 IP 地址都是同一个地址,这会导致速率限制的问题,因为 GoToSocial 使用客户端 IP 地址来执行速率限制。
|
||||
|
||||
## 总结:如何正确设置 `trusted-proxies`
|
||||
|
||||
如果你的 `trusted-proxies` 设置没有正确配置,你可能会在实例的网页视图中看到以下警告(v0.18.0及以上版本):
|
||||
|
||||
> 警告!此实例的配置中 trusted-proxies 的设置似乎不正确。这可能导致速率限制问题,进而导致联合问题。
|
||||
>
|
||||
> 如果你是实例管理员,你应该通过将 `SUGGESTED_IP_RANGE` 添加到你的 trusted-proxies 来修复此问题。
|
||||
|
||||
要解决这个问题,可以复制消息中的IP范围,并编辑你的 `config.yaml` 文件,将IP范围添加到你的 `trusted-proxies` 中。
|
||||
|
||||
!!! tip "即使你没有看到上述警告,你也可能会遇到速率限制!"
|
||||
如果你使用的是低于 v0.18.0 版本的 GoToSocial,或者你在 Cloudflare(不推荐) 这样的 CDN 之后运行,你将不会看到警告消息。相反,你会在 GoToSocial 日志中看到所有客户端的 IP 都是同一个地址。在这种情况下,可以将重复出现的客户端IP值作为`SUGGESTED_IP_RANGE`。
|
||||
|
||||
在下面例子中,我们假定`SUGGESTED_IP_RANGE`为`172.17.0.1/16`(默认的Docker桥接网络子网)。
|
||||
|
||||
修改之前(默认配置):
|
||||
|
||||
```yaml
|
||||
trusted-proxies:
|
||||
- "127.0.0.1/32"
|
||||
- "::1"
|
||||
```
|
||||
|
||||
修改之后(新配置):
|
||||
|
||||
```yaml
|
||||
trusted-proxies:
|
||||
- "172.17.0.1/16"
|
||||
- "127.0.0.1/32"
|
||||
- "::1"
|
||||
```
|
||||
|
||||
如果你使用[环境变量](../configuration/index.md#环境变量)来配置你的实例,可以通过设置环境变量`GTS_TRUSTED_PROXIES`为以逗号分隔的IP范围列表来配置`trusted-proxies`,如下所示:
|
||||
|
||||
```env
|
||||
GTS_TRUSTED_PROXIES="172.17.0.1/16,127.0.0.1/32,::1"
|
||||
```
|
||||
|
||||
如果你使用 docker compose,你的 docker-compose.yaml 文件在更改后应如下所示(注意 yaml 使用 `:` 而不是 `=`):
|
||||
|
||||
```yaml
|
||||
################################
|
||||
# 其他配置内容 #
|
||||
################################
|
||||
environment:
|
||||
############################
|
||||
# 其他环境变量 #
|
||||
############################
|
||||
## 对于反向代理设置:
|
||||
GTS_TRUSTED_PROXIES: "172.17.0.1/16,127.0.0.1/32,::1"
|
||||
################################
|
||||
# 其他配置内容 #
|
||||
################################
|
||||
```
|
||||
|
||||
一旦你完成了必要的配置更改,**重启你的实例**并刷新主页。
|
||||
|
||||
如果消息消失,则问题已解决!
|
||||
|
||||
如果你仍然看到警告消息,但显示了一个不同的建议添加到`trusted-proxies`的 IP 范围,那么重复上述步骤,在你的配置中添加新的建议 IP 范围。
|
||||
|
||||
!!! tip "Cloudflare 的 IP 地址列表"
|
||||
如果你在 GoToSocial 实例前面使用 CDN/代理,例如 Cloudflare (不推荐),那么你可能需要将一个或多个 Cloudflare IP 地址添加到你的 `trusted-proxies` 中,以便速率限制正常工作。你可以在这里找到Cloudflare 的 IP 地址列表: https://www.cloudflare.com/ips/
|
||||
|
||||
## 我可能无法正确配置 `trusted-proxies`,可以直接禁用警告吗?
|
||||
|
||||
在某些情况下,很难实际正确配置 `trusted-proxies` 来检测入站请求的真实客户端 IP,或者确保真实客户端 IP 是准确、但是仍显示为在私有网络内的。
|
||||
|
||||
例如,如果你在家用网络上运行 GoToSocial,且实例位于无法注入 `X-Forwarded-For` 标头的家庭互联网路由器之后,那么建议你添加到 `trusted-proxies` 的条目看起来会像 `192.168.x.x`,但将其添加到 `trusted-proxies` 后问题依然无法解决。
|
||||
|
||||
另一个例子是:你在家庭网络上运行 GoToSocial,GoToSocial 连接到家庭网络的路由器,并且你从同样在你家庭网络设备(比如笔记本或手机)上访问 Web 前端。在这种情况下,你的路由器可能会直接将你发送到你的 GoToSocial 实例,且你的请求不会离开家用网络,因此 GtS 将正确地认为*你的*客户端 IP 地址是一个私人网络地址,但*其他*从更广泛的互联网传入的请求将显示其真实的远程客户端 IP 地址。在这种情况下,`trusted-proxies` 的警告实际上不适用。
|
||||
|
||||
如果你已尝试编辑 `trusted-proxies` 设置,但仍看到警告,可能上面的一个例子适用于你。你可以通过以下两种方式之一继续:
|
||||
|
||||
### 为家庭网络添加速率限制例外(推荐)
|
||||
|
||||
如果 `trusted-proxies` 警告中的建议 IP 范围看起来像 `192.168.x.x`,但你在 GoToSocial 日志中仍看到其他客户端 IP 不以 `192.168` 开头,那么可以尝试只为家庭网络上的设备添加速率限制例外,同时对外部 IP 地址保持速率限制。
|
||||
|
||||
例如,如果你的建议是类似 `192.168.1.128/32`,那么将 `/32` 换为 `/24`,以便使范围覆盖 `192.168.1.0` -> `192.168.1.255`,并将其添加到 `config.yaml` 文件中的 `advanced-rate-limit-exceptions` 设置中。
|
||||
|
||||
默认设置(修改前):
|
||||
|
||||
```yaml
|
||||
advanced-rate-limit-exceptions: []
|
||||
```
|
||||
|
||||
设置修改后:
|
||||
|
||||
```yaml
|
||||
advanced-rate-limit-exceptions:
|
||||
- "192.168.1.128/24"
|
||||
```
|
||||
|
||||
如果你使用[环境变量](../configuration/index.md#环境变量)来配置实例,可以将环境变量 `GTS_ADVANCED_RATE_LIMIT_EXCEPTIONS` 设为以逗号分隔的 IP 范围列表,来配置 `advanced-rate-limit-exceptions`,如下所示:
|
||||
|
||||
```env
|
||||
GTS_ADVANCED_RATE_LIMIT_EXCEPTIONS="192.168.1.128/24"
|
||||
```
|
||||
|
||||
如果使用 docker compose,修改后的 docker-compose.yaml 文件应如下所示(注意 yaml 使用 `: ` 而不是 `=`):
|
||||
|
||||
```yaml
|
||||
################################
|
||||
# 其他配置内容 #
|
||||
################################
|
||||
environment:
|
||||
############################
|
||||
# 其他环境变量 #
|
||||
############################
|
||||
GTS_ADVANCED_RATE_LIMIT_EXCEPTIONS: "192.168.1.128/24"
|
||||
################################
|
||||
# 其他配置内容 #
|
||||
################################
|
||||
```
|
||||
|
||||
完成必要的配置更改后,**重启你的实例**并刷新主页。
|
||||
|
||||
### 完全关闭速率限制(最后手段)
|
||||
|
||||
如果其他方法无效,你可以完全禁用速率限制,这也会禁用 `trusted-proxies` 检查和警告。
|
||||
|
||||
!!! warning "警告"
|
||||
完全关闭速率限制应被视为最后的手段,因为速率限制有助于保护你的实例免受骚扰信息和爬虫攻击。
|
||||
|
||||
要关闭速率限制,请在 `config.yaml` 中将 `advanced-rate-limit-requests` 设置为 0。
|
||||
|
||||
默认配置前:
|
||||
|
||||
```yaml
|
||||
advanced-rate-limit-requests: 300
|
||||
```
|
||||
|
||||
设置后:
|
||||
|
||||
```yaml
|
||||
advanced-rate-limit-requests: 0
|
||||
```
|
||||
|
||||
如果你使用[环境变量](../configuration/index.md#环境变量)来配置实例,可以通过将环境变量 `GTS_ADVANCED_RATE_LIMIT_REQUESTS` 设置为 0,来配置 `advanced-rate-limit-requests`,如下所示:
|
||||
|
||||
```env
|
||||
GTS_ADVANCED_RATE_LIMIT_REQUESTS="0"
|
||||
```
|
||||
|
||||
如果使用 docker compose,改变后的 docker-compose.yaml 文件应如下所示(注意 yaml 使用 `: ` 而不是 `=`):
|
||||
|
||||
```yaml
|
||||
################################
|
||||
# 其他配置内容 #
|
||||
################################
|
||||
environment:
|
||||
############################
|
||||
# 其他环境变量 #
|
||||
############################
|
||||
GTS_ADVANCED_RATE_LIMIT_REQUESTS: "0"
|
||||
################################
|
||||
# 其他配置内容 #
|
||||
################################
|
||||
```
|
||||
|
||||
完成必要的配置更改后,**重启你的实例**并刷新主页。
|
|
@ -1,5 +1,13 @@
|
|||
# 行为体与行为体属性
|
||||
|
||||
## `Service` 与 `Person` 行为体
|
||||
|
||||
GoToSocial 将大多数账号视为[此处](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person)描述的 ActivityStreams `Person` 类型。
|
||||
|
||||
然而,被用户标记为机器人的账号将使用[此处](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-service)描述的 `Service` 类型。
|
||||
|
||||
这种类型的区分可供外站实例区分机器人账号和“普通”用户账号。
|
||||
|
||||
## 收件箱
|
||||
|
||||
GoToSocial 按照 [ActivityPub 规范](https://www.w3.org/TR/activitypub/#inbox),为行为体实现了收件箱。
|
||||
|
|
|
@ -47,6 +47,58 @@ GoToSocial 外发话题标签提供的 `href` URL 指向一个提供 `text/html`
|
|||
|
||||
GoToSocial 对给定 `text/html` 的内容不做任何保证,外站不应该将 URL 解释为规范的 ActivityPub ID/URI 属性。`href` URL 仅作为可能包含该话题标签更多信息的一个端点。
|
||||
|
||||
## 表情符号(Emoji)
|
||||
|
||||
GoToSocial 使用 `http://joinmastodon.org/ns#Emoji` 类型,以允许用户在贴文中添加自定义表情符号。
|
||||
|
||||
例如:
|
||||
|
||||
```json
|
||||
{
|
||||
"@context": [
|
||||
"https://gotosocial.org/ns",
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
{
|
||||
"Emoji": "toot:Emoji",
|
||||
"sensitive": "as:sensitive",
|
||||
"toot": "http://joinmastodon.org/ns#"
|
||||
}
|
||||
],
|
||||
"type": "Note",
|
||||
"content": "<p>这里有个臭烘烘的东西 -> :shocked_pikachu:</p>",
|
||||
[...],
|
||||
"tag": {
|
||||
"icon": {
|
||||
"mediaType": "image/png",
|
||||
"type": "Image",
|
||||
"url": "https://example.org/fileserver/01BPSX2MKCRVMD4YN4D71G9CP5/emoji/original/01AZY1Y5YQD6TREB5W50HGTCSZ.png"
|
||||
},
|
||||
"id": "https://example.org/emoji/01AZY1Y5YQD6TREB5W50HGTCSZ",
|
||||
"name": ":shocked_pikachu:",
|
||||
"type": "Emoji",
|
||||
"updated": "2022-11-17T11:36:05Z"
|
||||
}
|
||||
[...]
|
||||
}
|
||||
```
|
||||
|
||||
上述 `Note` 的 `content` 中的文本 `:shocked_pikachu:` 应当被客户端替换为表情符号图片的小型(内联)版本,在渲染 `Note` 时一并向用户展示。
|
||||
|
||||
表情符号的 `updated` 和 `icon.url` 属性可被外站实例用于判断它们对 GoToSocial 表情符号图片的表示是否是最新版本。必要时也可以在其 `id` URI 间接引用 `Emoji`,以便外站对照检查它们缓存的表情符号元数据是否未最新版本。
|
||||
|
||||
默认情况下,GoToSocial 对可以上传和发送的表情符号图片的大小设置了 50kb 的限制,并对可以联合并传入的表情符号图片大小设置了 100kb 的限制,但这两项设置都可由用户配置。
|
||||
|
||||
GoToSocial 可以发送和接收类型为 `image/png`、`image/jpeg`、`image/gif` 和 `image/webp` 的表情符号图片。
|
||||
|
||||
!!! info "附注"
|
||||
请注意,`tag` 属性可以是对象的数组,也可以是单个对象。
|
||||
|
||||
### `null` / 空 `id` 属性
|
||||
|
||||
一些服务端软件,如 Akkoma,将表情符号包含为贴文中的[匿名对象](https://www.w3.org/TR/activitypub/#obj-id)。也就是说,它们将 `id` 属性设置为 `null`,以表明该表情符号不能在任何特定的端点被间接引用。
|
||||
|
||||
在接收到这样的表情符号时,GoToSocial 会在数据库中为该表情符号生成一个伪 id,格式为 `https://[host]/dummy_emoji_path?shortcode=[shortcode]`,例如,`https://example.org/dummy_emoji_path?shortcode=shocked_pikachu`。
|
||||
|
||||
## 提及
|
||||
|
||||
GoToSocial 用户可以在贴文中使用 `@[用户名]@[域名]` 格式提及其他用户。例如,如果一个 GoToSocial 用户想提及实例 `example.org` 上的用户 `someone`,可以在贴文中包含 `@someone@example.org`。
|
||||
|
@ -160,14 +212,14 @@ GoToSocial 在解析传入的 `Object` 时使用 `content` 和 `contentMap` 属
|
|||
|
||||
如果 `contentMap` 有多个条目,则无法确定贴文的意图内容和语言,因为映射顺序不可预测。在这种情况下,尝试从 GoToSocial 实例的[配置语言](../configuration/instance.md)中选择与其中一种语言匹配的语言和内容条目。如果无法通过这种方式匹配语言,则从 `contentMap` 中随机选择一个语言和内容条目作为“主要”语言和内容。
|
||||
|
||||
!!! Note
|
||||
!!! note "注意"
|
||||
在上述所有情况下,如果推断的语言无法解析为有效的 BCP47 语言话题标签,则语言将回退为未知。
|
||||
|
||||
## 互动规则
|
||||
|
||||
GoToSocial 使用 `interactionPolicy` 属性告知外站给定帖文允许的互动类型(有前提)。
|
||||
|
||||
!!! danger
|
||||
!!! danger "危险"
|
||||
|
||||
互动规则旨在限制用户贴文上用户不希望的回复和其他互动的有害影响(例如,“回复家(reply guys)” —— 不请自来地发表冒失回复的人)。
|
||||
|
||||
|
@ -229,7 +281,7 @@ GoToSocial 使用 `interactionPolicy` 属性告知外站给定帖文允许的互
|
|||
|
||||
### 指定无人能进行的操作
|
||||
|
||||
!!! note
|
||||
!!! note "注意"
|
||||
即使规则指定无人可互动,GoToSocial 仍做出默认假设。参见[默认假设](#默认假设)。
|
||||
|
||||
空数组或缺少/空的键表示无人能进行此互动。
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
在部署 GoToSocial 之前,有几个关键点需要你仔细考虑,因为这些选择将影响你如何运行和管理 GoToSocial。
|
||||
|
||||
!!! danger
|
||||
!!! danger "危险"
|
||||
|
||||
在同一域名上切换不同实现是不被 Fediverse 支持的。这意味着如果你在 example.org 上运行 GoToSocial,而尝试切换到其他实现如 Pleroma/Akkoma、Misskey/Calckey 等,你会遇到联合问题。
|
||||
|
||||
|
@ -24,7 +24,7 @@ GoToSocial 致力于为在小型设备上运行的使用场景优化,因此我
|
|||
|
||||
你应该在这种情况下预留一些余量,若有需要,可以[配置一些交换内存](#交换内存)。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
在内存受限的环境中,你可以将 `cache.memory-target` 设置为低于默认的 100MB (查看数据库配置选项[这里](../configuration/database.md#settings))。设置为 50MB 已被证明可以正常运行。
|
||||
|
||||
这将使总内存使用稍微降低,但代价是某些请求的延迟略高,因为 GtS 需要更频繁地访问数据库。
|
||||
|
@ -46,7 +46,7 @@ GoToSocial 使用存储来保存其数据库文件,以及存储和服务媒体
|
|||
|
||||
对于媒体存储,以及[缓存的外站媒体文件存储](../admin/media_caching.md),你应该预算大约 5GB-10GB 的空间。GoToSocial 会自动执行自我清理,在一段时间后从缓存中删除未使用的外站媒体。如果存储空间是个问题,你可以[调整媒体清理行为](../admin/media_caching.md#清理)以更频繁地清理和/或减少外站媒体的缓存时间。
|
||||
|
||||
!!! info
|
||||
!!! info "附注"
|
||||
如果你的 sqlite.db 文件或 Postgres 容量在一开始增长很快,请不要惊慌,这是正常的。当你首次部署实例并开始联合时,你的实例会迅速发现并存储来自其他实例的账号和贴文。然而,随着实例的长期部署,这种增长会逐渐减缓,因为你会自然而然地看到更少的新账号(即,你的实例尚未见过并因此尚未在数据库中存储的账号)。
|
||||
|
||||
### 单板计算机
|
||||
|
@ -106,7 +106,7 @@ SQLite 是默认的驱动,并已被证明在 1-30 用户范围内的实例表
|
|||
|
||||
无论你选择哪种数据库驱动,为了获得良好的性能,它们都应在快速、稳定的低延迟存储上运行。虽然可以在网络附加存储上运行数据库,但这会增加可变延迟和网络拥堵,还有源存储上的潜在 I/O 争用。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
请[备份你的数据库](../admin/backup_and_restore.md)。数据库包含实例和任何用户账户的加密密钥。如果丢失这些密钥,你将无法再次从同一域进行联合!
|
||||
|
||||
## 域名
|
||||
|
@ -119,7 +119,7 @@ SQLite 是默认的驱动,并已被证明在 1-30 用户范围内的实例表
|
|||
|
||||
如果你打算这样部署 GoToSocial 实例,请阅读[分域部署](../advanced/host-account-domain.md)文档以了解详细信息。
|
||||
|
||||
!!! danger
|
||||
!!! danger "危险"
|
||||
无法在联合已经事实发生后安全地更改实例域名和账号域名。这需要重新生成数据库,并在任何已联合的服务器造成混乱情况。一旦你的实例域名和账号域名设置好,便不可更改。
|
||||
|
||||
## TLS
|
||||
|
@ -128,7 +128,7 @@ SQLite 是默认的驱动,并已被证明在 1-30 用户范围内的实例表
|
|||
|
||||
GoToSocial 内置 Lets Encrypt 证书配置支持。它也可以从磁盘加载证书。如果你有连接到 GoToSocial 的反向代理,可以在代理层处理 TLS。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
请确保配置使用现代版本的 TLS,TLSv1.2 及更高版本,以确保服务器和客户端之间的通信安全。当 GoToSocial 处理 TLS 终端时,这会自动为你配置。如果使用反向代理,请使用 [Mozilla SSL 配置生成器](https://ssl-config.mozilla.org/)。
|
||||
|
||||
## 端口
|
||||
|
@ -140,7 +140,7 @@ GoToSocial 需要开放端口 `80` 和 `443`。
|
|||
|
||||
如果你无法在机器上开放 `443` 和 `80` 端口,不要担心!你可以在 GoToSocial 中配置这些端口,但还需要配置端口转发,以将 `443` 和 `80` 上的流量准确转发到你选择的端口。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
你应该在机器上配置防火墙,并配置一些防范暴力 SSH 登录尝试的保护措施。参阅我们的[防火墙文档](../advanced/security/firewall.md)以获取配置建议和可帮助你的工具。
|
||||
|
||||
## 集群 / 多节点部署
|
||||
|
@ -167,7 +167,7 @@ GoToSocial 不支持[集群或任何形式的多节点部署](https://github.com
|
|||
|
||||
虽然可以在没有交换内存的情况下运行系统,但为了安全地做到这一点并确保一致的性能和服务可用性,你需要相应调整内核、系统和工作负载。这需要对内核的内存管理系统及你所运行的工作负载的内存使用模式有良好的理解。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
交换内存用于确保内核可以高效地回收内存。这在系统没有经历内存争用时也很有用,比如在进程启动时仅使用过的内存腾出。这允许更多活跃使用的东西被缓存于内存中。内存交换不是让你的程序变慢的原因。内存争用才是造成缓慢的原因。
|
||||
|
||||
[sysctl]: https://man7.org/linux/man-pages/man8/sysctl.8.html
|
||||
|
|
|
@ -44,7 +44,7 @@ nano docker-compose.yaml
|
|||
* `snapshot`:指向当前在主分支上的代码。不保证稳定,可能经常出错。谨慎使用。
|
||||
* `vX.Y.Z`:发布标签。这指向 GoToSocial 的特定、稳定的版本。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
`latest` 和 `snapshot` 标签是动态标签,而 `vX.Y.Z` 标签是固定的。拉取动态标签的结果可能每天都会变化。同一系统上的 `latest` 可能与不同系统上的 `latest` 不同。建议使用 `vX.Y.Z` 标签,以便你始终确切知道运行的是 GoToSocial 的哪个版本。发布列表可以在[这里](https://github.com/superseriousbusiness/gotosocial/releases)找到,最新的发布在顶部。
|
||||
|
||||
### 主机
|
||||
|
@ -87,7 +87,7 @@ nano docker-compose.yaml
|
|||
如果你决定稍后设置/更改这些变量,请确保在更改后重新创建 GoToSocial 实例容器。
|
||||
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
|
||||
有关将 config.yaml 文件中的变量名称转换为环境变量的帮助,请参阅[配置部分](../../configuration/index.md#environment-variables)。
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ cd /gotosocial
|
|||
|
||||
现在,下载与你运行的操作系统和架构相对应的最新 GoToSocial 发行版压缩包。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
你可以在[这里](https://github.com/superseriousbusiness/gotosocial/releases)找到按发布时间排列的发布列表,最新的发行版位于最上面。
|
||||
|
||||
例如,下载适用于 64 位 Linux 的版本:
|
||||
|
@ -52,7 +52,7 @@ tar -xzf gotosocial_${GTS_VERSION}_${GTS_TARGET}.tar.gz
|
|||
|
||||
这将在你的当前目录放置 `gotosocial` 二进制文件,以及包含网页前端资源的 `web` 文件夹和包含示例配置文件的 `example` 文件夹。
|
||||
|
||||
!!! danger
|
||||
!!! danger "危险"
|
||||
如果你想使用基于当前主分支代码的 GoToSocial 快照构建,可以从[这里](https://minio.s3.superseriousbusiness.org/browser/gotosocial-snapshots)下载最近的二进制 .tar.gz 文件(基于提交哈希)。仅在你很清楚自己的操作时使用,否则请使用稳定版。
|
||||
|
||||
## 编辑配置文件
|
||||
|
|
|
@ -48,7 +48,7 @@ sudo systemctl restart gotosocial.service
|
|||
|
||||
### 使用 mod_md 启用 TLS
|
||||
|
||||
!!! note
|
||||
!!! note "注意"
|
||||
`mod_md` 自 Apache 2.4.30 开始可用,仍被视为实验性的。实际上,它在实践中表现良好,是最便捷的方法。
|
||||
|
||||
现在我们将配置 Apache HTTP 服务器来处理 GoToSocial 请求。
|
||||
|
@ -166,7 +166,7 @@ sudo systemctl restart apache2
|
|||
|
||||
### 使用外部管理证书启用 TLS
|
||||
|
||||
!!! note
|
||||
!!! note "注意"
|
||||
我们有关于如何[配置 TLS 证书](../../advanced/certificates.md)的额外文档,其中还提供了不同发行版的其他内容和教程链接,可能值得查看。
|
||||
|
||||
如果你更喜欢手动设置或使用不同服务(如 Certbot)来管理 SSL,可以为你的 Apache HTTP 服务器使用更简单的设置。
|
||||
|
|
|
@ -11,7 +11,7 @@ GoToSocial 可以直接暴露到互联网上。不过,许多人更愿意使用
|
|||
* 如果你使用了 Lets Encrypt,在 GoToSocial 中禁用它。将 `letsencrypt-enabled` 设置为 `false`
|
||||
* 配置反向代理以处理 TLS 并将请求代理到 GoToSocial
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
不要更改 `host` 配置选项的值。这必须保持为其他实例在互联网上看到的实际域名。相反,改变 `bind-address` 并更新 `port` 和 `trusted-proxies`。
|
||||
|
||||
### 容器
|
||||
|
@ -41,3 +41,7 @@ GoToSocial 可以直接暴露到互联网上。不过,许多人更愿意使用
|
|||
使用反向代理时,必须特别注意允许 WebSockets 正常工作。因为许多客户端应用程序使用 WebSockets 来流式传输你的时间线。WebSockets 不用于联合。
|
||||
|
||||
请确保阅读 [WebSocket](websocket.md) 文档,并相应地配置你的反向代理。
|
||||
|
||||
## 可信代理
|
||||
|
||||
使用反向代理时,可能会遇到速率限制和 `trusted-proxies` 相关的问题。如有任何问题,请查阅[可信代理](../../configuration/trusted_proxies.md)文档。
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
要使用 NGINX 作为 GoToSocial 的反向代理,你需要在服务器上安装它。如果你打算让 NGINX 处理 TLS,你还需要[配置 TLS 证书](../../advanced/certificates.md)。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
通过在 `server` 块中包含 `http2 on;` 来启用 NGINX 的 HTTP/2。这样可以加快客户端的体验。请参阅 [ngx_http_v2_module 文档](https://nginx.org/en/docs/http/ngx_http_v2_module.html#example)。
|
||||
|
||||
NGINX 已为[多个发行版打包](https://repology.org/project/nginx/versions)。你很可能可以使用发行版的包管理器来安装它。你也可以使用 Docker Hub 上发布的[官方 NGINX 镜像](https://hub.docker.com/_/nginx)通过容器运行 NGINX。
|
||||
|
@ -112,7 +112,7 @@ sudo systemctl restart nginx
|
|||
|
||||
## 设置 TLS
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
我们有关于如何[配置 TLS 证书](../../advanced/certificates.md)的附加文档,还提供了有关不同发行版的附加内容和教程链接,值得一看。
|
||||
|
||||
你现在可以运行 certbot,它将引导你完成启用 https 的步骤。
|
||||
|
@ -145,7 +145,7 @@ sudo systemctl start gotosocial
|
|||
|
||||
如果你再次打开 NGINX 配置,你会发现 Certbot 添加了一些额外的行。
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
根据你设置 Certbot 时选择的选项,以及使用的 NGINX 版本,可能会有所不同。
|
||||
|
||||
```nginx
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
例如,将用户提升为管理员后,你需要重启 GoToSocial 服务器,以便从数据库加载新值。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
|
||||
要查看其他可用的 CLI 命令,请点击[这里](../admin/cli.md)。
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ nav:
|
|||
- "配置":
|
||||
- "configuration/index.md"
|
||||
- "configuration/general.md"
|
||||
- "configuration/trusted_proxies.md"
|
||||
- "configuration/database.md"
|
||||
- "configuration/web.md"
|
||||
- "configuration/instance.md"
|
||||
|
@ -87,6 +88,7 @@ nav:
|
|||
- "admin/signups.md"
|
||||
- "admin/federation_modes.md"
|
||||
- "admin/domain_blocks.md"
|
||||
- "admin/domain_permission_subscriptions.md"
|
||||
- "admin/request_filtering_modes.md"
|
||||
- "admin/robots.md"
|
||||
- "admin/cli.md"
|
||||
|
|
|
@ -148,7 +148,7 @@ Golang 的一个特点是,它所依赖的源代码管理路径与 `go.mod` 中
|
|||
>
|
||||
> 把你的派生分支添加为 origin:
|
||||
>
|
||||
> `git remote add origin git@github.com/yourgithubname/gotosocial`
|
||||
> `git remote add origin git@github.com:yourgithubname/gotosocial`
|
||||
>
|
||||
|
||||
在第一次构建项目之前,一定要运行 `git fetch`。
|
||||
|
@ -488,7 +488,7 @@ GoToSocial 使用 [go-swagger](https://goswagger.io) 根据代码注释生成 Sw
|
|||
如果你更改了任何 API 路径上的 Swagger 注释,可以通过运行以下命令在 `./docs/api/swagger.yaml` 生成一个新的 Swagger 文件:
|
||||
|
||||
```bash
|
||||
swagger generate spec --scan-models --exclude-deps -o docs/api/swagger.yaml
|
||||
go run github.com/go-swagger/go-swagger/cmd/swagger generate spec --scan-models --exclude-deps --output docs/api/swagger.yaml
|
||||
```
|
||||
|
||||
### CI/CD 配置
|
||||
|
|
|
@ -17,7 +17,7 @@ GoToSocial 是一个用 Golang 编写的 [ActivityPub](https://activitypub.rocks
|
|||
|
||||
要从源代码构建,请查看 [CONTRIBUTING.md](https://github.com/superseriousbusiness/gotosocial/blob/main/docs/locales/zh/repo/CONTRIBUTING.md) 文件。
|
||||
|
||||
这是实例首页的截图!
|
||||
这是实例首页的截图!你也可以看一看本项目在 GoToSocial 上的官方账号: [https://gts.superseriousbusiness.org/@gotosocial](https://gts.superseriousbusiness.org/@gotosocial)。
|
||||
|
||||

|
||||
<!--overview-end-->
|
||||
|
@ -126,7 +126,7 @@ GoToSocial 提供公开、不列出/悄悄公开、仅粉丝和私信(最好
|
|||
|
||||
### 回复控制
|
||||
|
||||
GoToSocial 允许你通过 [互动规则](https://docs.gotosocial.org/zh-cn/latest/user_guide/settings/#default-interaction-policies) 选择谁可以回复你的贴文。你可以选择允许任何人回复贴文,仅允许朋友回复,等等。
|
||||
GoToSocial 允许你通过 [互动规则](https://docs.gotosocial.org/zh-cn/latest/user_guide/settings/#默认互动规则) 选择谁可以回复你的贴文。你可以选择允许任何人回复贴文,仅允许朋友回复,等等。
|
||||
|
||||

|
||||
|
||||
|
@ -146,7 +146,7 @@ GoToSocial 允许你选择将个人资料暴露为 RSS 订阅源,这样人们
|
|||
|
||||
### 主题与自定义 CSS
|
||||
|
||||
用户可以为他们的账户页 [选择多种有趣的主题](https://docs.gotosocial.org/zh-cn/latest/user_guide/settings/#select-theme),或甚至编写自己的 [自定义 CSS](https://docs.gotosocial.org/zh-cn/latest/user_guide/settings/#custom-css)。
|
||||
用户可以为他们的账户页 [选择多种有趣的主题](https://docs.gotosocial.org/zh-cn/latest/user_guide/settings/#选择主题),或甚至编写自己的 [自定义 CSS](https://docs.gotosocial.org/zh-cn/latest/user_guide/settings/#自定义-CSS)。
|
||||
|
||||
管理员也可以轻松地为用户 [添加自定义主题](https://docs.gotosocial.org/zh-cn/latest/admin/themes/) 供用户选择。
|
||||
|
||||
|
@ -225,10 +225,11 @@ GoToSocial 仅需约 250-350MiB 的 RAM,并且只要求极少的 CPU 频率,
|
|||
|
||||
### 隐私+安全功能
|
||||
|
||||
- 内置 [Let's Encrypt](https://letsencrypt.org/) 的自动使用 HTTPS 支持。
|
||||
- 严格执行贴文可见性和屏蔽逻辑。
|
||||
- 导入与导出允许联合实例列表和拒绝联合实例列表。订阅社区创建的屏蔽列表(类似于用于实例间联合的广告拦截器!)(功能仍在进行中)。
|
||||
- 严格执行贴文隐私保护与屏蔽逻辑。
|
||||
- [支持配置通过网页访问账户时的贴文的可见范围](https://docs.gotosocial.org/zh-cn/latest/user_guide/settings/#个人资料上显示的贴文可见性级别)。
|
||||
- [导入/导出](https://docs.gotosocial.org/zh-cn/latest/admin/settings/#导入导出) 社区创建的域名允许和域名阻止列表,并[订阅](https://docs.gotosocial.org/zh-cn/latest/admin/domain_permission_subscriptions)这些列表。
|
||||
- HTTP 签名认证:GoToSocial 在发送和接收消息时要求 [HTTP 签名](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12),以确保消息不能被篡改,身份不能被伪造。
|
||||
- 内置 [Let's Encrypt](https://letsencrypt.org/) 的自动使用 HTTPS 支持。
|
||||
|
||||
### 多种联合模式
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
- [x] **v2 过滤规则** -- 实现过滤器 API 的第二版。
|
||||
- [x] **静音账户** -- 静音账户以防止其帖文出现在主页时间线上(可选:限制时间段)。
|
||||
- [x] **无评论区的帖文** -- 设计无评论区帖文的相关逻辑,让用户创建无评论区的帖文。
|
||||
- [ ] **屏蔽/允许列表订阅** -- 允许实例管理员订阅纯文本的示例屏蔽/允许列表。(大部分工作已经完成)
|
||||
- [x] **屏蔽/允许列表订阅** -- 允许实例管理员为其实例订阅屏蔽/允许列表。
|
||||
- [x] **私信对话视图** -- 让用户能够轻松浏览他们参与的所有私信对话。
|
||||
- [ ] **Oauth 令牌管理** -- 通过设置面板创建/查看/吊销 OAuth 令牌。
|
||||
- [ ] **贴文编辑支持** -- 编辑已创建的贴文,而无需删除并重新编辑。并正确地将编辑传播出去。
|
||||
|
|
|
@ -6,10 +6,10 @@ GoToSocial 支持使用 `Move` 活动进行账号迁移。
|
|||
|
||||
迁移是软件无关的,因此你可以将账号迁移到其它软件或从任何支持 `Move` 活动的软件发起迁移,无论具体的软件是什么。例如,你可以将 GoToSocial 账号迁移到 Mastodon 账号,将 Mastodon 账号迁移到 GoToSocial 账号,将 GoToSocial 账号迁移到或从 Akkoma、Misskey、GoToSocial 等。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
根据目标账号所在软件的不同,目标账号的 URI(用于别名和迁移)应该类似于 `https://mastodon.example.org/users/account_you_are_moving_to`。如果你不确定使用哪种格式,请咨询你要迁移或设置别名的实例管理员。
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
GoToSocial 要求 7 天的账号迁移冷却期,以防止过度切换实例(以及潜在的屏蔽规避风险)。
|
||||
|
||||
如果任何一个发起新迁移尝试的账号在最近七天内已迁移,GoToSocial 将拒绝进行迁移,直到上一次迁移过去七天位置。
|
||||
|
@ -71,8 +71,8 @@ GoToSocial 支持使用 `Move` 活动进行账号迁移。
|
|||
|
||||
一旦触发从其他账号到 GoToSocial 账号的迁移,你唯一需要做的就是在新(GoToSocial)账号上接受来自旧账号粉丝的关注请求。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
为了省去麻烦,可以考虑在触发迁移前将 GoToSocial 账号设置为不需要批准新的关注请求。迁移完成后再开启关注请求审核。否则,你将需要手动批准每个从旧账号迁移的粉丝。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
迁移账号后,可能需要将之前账号的关注列表导入 GoToSocial 账号。[在此查看](./settings.md#import)如何通过设置面板完成此操作的详细信息。
|
||||
|
|
|
@ -36,7 +36,7 @@ GoToSocial 为贴文提供 Mastodon 风格的隐私设置。从最私密到最
|
|||
|
||||
### 互关可见
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
目前暂时无法将帖文可见性设为“互关可见”。
|
||||
|
||||
`互关可见` 的贴文只会显示给贴文作者和与作者*互相关注*的人。换句话说,只有在满足两个条件时,其他人才能看到:
|
||||
|
@ -135,14 +135,14 @@ GoToSocial 允许你在贴文中附加媒体文件,大多数客户端会在贴
|
|||
|
||||
为了避免泄漏你的位置信息,GoToSocial 努力在上传媒体时通过清零 Exif 数据点移除 Exif 信息。
|
||||
|
||||
!!! danger
|
||||
!!! danger "危险"
|
||||
为了方便和保护隐私,GoToSocial 在上传图片文件时会自动移除 Exif 标签。然而,**无法自动移除 mp4 视频的 Exif 数据**(参见 [#2577](https://github.com/superseriousbusiness/gotosocial/issues/2577))。
|
||||
|
||||
在你将视频上传至 GoToSocial 之前,建议确保该视频的 Exif 数据标签已经被移除。你可以在线找到多种工具和服务来做到这一点。
|
||||
|
||||
为防止 Exif 位置信息在一开始被写入图片或视频中,你还可以关闭设备摄像头应用中的位置标记(通常称为地理标记)。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
即使你在上传图片或视频之前已完全移除所有 Exif 元数据,恶意用户仍然可以通过媒体本身的内容推断出你的位置信息。
|
||||
|
||||
如果你属于在生产中有保密需要的组织,或正在被跟踪或监视,你可能需要考虑不要发布任何可能含有你位置线索的媒体。
|
||||
|
@ -285,6 +285,9 @@ GoToSocial 允许你在贴文中附加媒体文件,大多数客户端会在贴
|
|||
|
||||
你可以在 GoToSocial 贴文中包含任意数量的话题标签,而且每个话题标签的长度限制为 100 个字符。
|
||||
|
||||
!!! tip "提示"
|
||||
要结束一个话题标签,你只需在话题标签名后输入空格。例如,在文本 `这道 #鸡汤 十分美味` 中,话题标签由空格终止,因此 `#鸡汤` 成为话题标签。但是,你也可以使用管道字符 `|`,或使用 Unicode 字符 `\u200B` (零宽不换行空格)或 `\uFEFF` (零宽空格),来创建“词语片段”话题标签。例如,在 `这道 #鸡|汤 十分美味` 中,只有 `#鸡` 成为话题标签。同理,对于文本 `这道 #鸡汤 十分美味` (`鸡` 和 `汤` 之间有一个零宽空格),只有 `#鸡` 成为话题标签。有关零宽空格的更多信息,参见:https://en.wikipedia.org/wiki/Zero-width_space。
|
||||
|
||||
## 输入净化
|
||||
|
||||
为了不传播脚本、漏洞以及不稳定的 HTML,GoToSocial 执行以下类型的输入净化:
|
||||
|
|
|
@ -88,14 +88,14 @@ GoToSocial 提供主题供你选择,以更改账户的外观和氛围。
|
|||
|
||||
此设置不会影响你的贴文在 ActivityPub 协议和客户端中的可见性,因此即便你选择不在网页版账户页显示任何贴文,只要他人是你的粉丝、你的贴文被转发到他们的时间线,或使用链接搜索你的某个贴文,他们仍然可以看到的贴文。
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
请注意,此设置的更改也会应用于之前的贴文。
|
||||
|
||||
也就是说,如果你之前发布了一条“不列出”可见性的贴文,而当时你的网页版账户页被设置为仅显示公开贴文,此时如果你更改此设置为一并显示公开和不列出,那你之前发布的“不列出”贴文将会与公开贴文一起显示在你的网页版账户页上。
|
||||
|
||||
同样地,如果你选择不显示任何贴文,那么所有贴文将从你的网页版账户页中隐藏,无论它们是在何时创建,也无论当时此选项被设置为什么。这种情况将持续直到你再次更改此设置。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
结合(域名)屏蔽,如果有人通过公开贴文骚扰你,这是一种很好的“紧急”设置。虽然它不会阻止在 ActivityPub 客户端中可以看到你的贴文的人,但至少会防止他们无需身份验证就通过浏览器点击查看你的贴文,并通过 URL 轻松与他人分享。
|
||||
|
||||
#### 手动批准关注请求(即锁定帐户)
|
||||
|
@ -121,10 +121,10 @@ GoToSocial 提供主题供你选择,以更改账户的外观和氛围。
|
|||
|
||||
将可发现性标记打开可能需要一周或更长时间才会生效,账户不会立即出现在搜索引擎结果中。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
为了避免暴露给爬虫,新帐户的可发现性默认为 false。但对于希望被抓取的面向公众的帐户,将其设置为 true 是有用的。
|
||||
|
||||
!!! info
|
||||
!!! info "附注"
|
||||
可发现性设置是关于**账户的可发现性**,而不是贴文的可被搜索性。这与 Mastodon 实例或其他使用全文搜索的实例的贴文索引无关!
|
||||
|
||||
#### 启用公开贴文的 RSS 源
|
||||
|
@ -133,7 +133,7 @@ GoToSocial 提供主题供你选择,以更改账户的外观和氛围。
|
|||
|
||||
此源仅包括设置为“公开”的贴文(参见 [隐私设置](./posts.md#隐私设置))。
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
公开您的 RSS 源允许*任何人*匿名订阅您公开贴文的更新,绕过关注和关注请求。
|
||||
|
||||
#### 隐藏你关注/被关注的人
|
||||
|
@ -152,7 +152,7 @@ GoToSocial 提供主题供你选择,以更改账户的外观和氛围。
|
|||
|
||||
请参阅 [自定义 CSS](./custom_css.md) 页面,了解有关为账户编写自定义 CSS 的一些提示。
|
||||
|
||||
!!! tip
|
||||
!!! tip "提示"
|
||||
你在此框中添加的任何自定义 CSS 都将在*选择主题之后*应用,因此你可以选择一个喜欢的预设主题,然后进行自己的调整!
|
||||
|
||||
## 贴文
|
||||
|
@ -196,7 +196,7 @@ markdown 设置表示你的贴文应被按 Markdown 格式解析,这是一种
|
|||
|
||||
如果你想将所有规则重置为初始默认值,可以点击 `重置为默认值` 按钮。
|
||||
|
||||
!!! danger
|
||||
!!! danger "危险"
|
||||
虽然 GoToSocial 尊重互动规则,但不能保证其他服务端软件也会这样做,即使你的实例禁止某些互动,其他服务器上的账户可能仍会向其粉丝发送(被禁止的)贴文回复和转发。
|
||||
|
||||
随着更多 ActivityPub 服务端推出互动规则支持,这个问题有望减少,但在此期间,GoToSocial 只能在“尽力而为”范围内进行尝试,以根据你设定的规则限制与贴文的互动。
|
||||
|
@ -209,14 +209,14 @@ markdown 设置表示你的贴文应被按 Markdown 格式解析,这是一种
|
|||
|
||||
输入新电子邮箱地址,并点击“更改电子邮箱地址”后,必须打开新电子邮件地址的收件箱,并通过提供的链接确认地址。完成后,你的电子邮箱地址更改将被确认。
|
||||
|
||||
!!! info
|
||||
!!! info "附注"
|
||||
如果你的实例使用 OIDC 作为授权/身份提供商,你可以通过设置面板更改电子邮箱地址,但只会影响 GoToSocial 用于联系你的电子邮箱地址,而不会更改用于登录账户的电子邮箱地址。要更改此项,应联系你的 OIDC 提供商。
|
||||
|
||||
### 更改密码
|
||||
|
||||
你可以使用面板的更改密码部分为账户设置新密码。出于安全原因,你必须提供当前密码以验证更改。
|
||||
|
||||
!!! info
|
||||
!!! info "附注"
|
||||
如果你的实例使用 OIDC 作为授权/身份提供商,你将无法通过 GoToSocial 设置面板更改密码,此时应联系你的 OIDC 提供商。
|
||||
|
||||
有关 GoToSocial 如何管理密码的更多信息,请参阅[密码管理文档](./password_management.md)。
|
||||
|
@ -249,7 +249,7 @@ markdown 设置表示你的贴文应被按 Markdown 格式解析,这是一种
|
|||
|
||||
然后,使用下拉菜单选择通过 CSV 文件上传的数据类型。
|
||||
|
||||
!!! warning
|
||||
!!! warning "警告"
|
||||
在选择“类型”时要小心,否则可能会意外封禁你计划关注的一堆账户,反之亦然!
|
||||
|
||||
然后,选择是要**合并**新数据到 GoToSocial 账户中该类型的现有数据,还是要用 CSV 文件中包含的数据**覆盖**现有数据。
|
||||
|
@ -264,5 +264,5 @@ markdown 设置表示你的贴文应被按 Markdown 格式解析,这是一种
|
|||
|
||||
合并和覆盖操作都是幂等的,这通常意味着现有数据和 CSV 文件中的重复条目不会产生问题,如果需要重试导入,可以多次导入相同的数据。
|
||||
|
||||
!!! info
|
||||
!!! info "附注"
|
||||
由于各种原因,通过导入不可能一定会重新创建上传的 CSV 文件中的每个条目。例如,假设你试图导入包含 `example_account` 的关注 CSV,但 `example_account` 的实例已下线,或者它们的实例封禁了你的实例,或你的实例封禁了它们的实例等。在这种情况下,将无法创建对 `example_account` 的关注。
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 155 KiB |
Binary file not shown.
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 120 KiB |
|
@ -285,6 +285,9 @@ For accessibility reasons, it is considerate to use upper camel case when you're
|
|||
|
||||
You can include as many hashtags as you like within a GoToSocial post, and each hashtag has a length limit of 100 characters.
|
||||
|
||||
!!! tip
|
||||
To end a hashtag, you can simply use a space, for example in the text `this #soup rules`, the hashtag is terminated by a space so `#soup` becomes the hashtag. However, you can also use a pipe character `|`, or the unicode characters `\u200B` (zero-width no-break space) or `\uFEFF` (zero-width space), to create "partial-word" hashtags. For example, with input text `this #so|up rules`, only the `#so` part becomes the hashtag. Likewise, with the input text `this #soup rules`, which contains an invisible zero-width space after the o and before the u, only the `#so` part becomes the hashtag. See here for more information on zero-width spaces: https://en.wikipedia.org/wiki/Zero-width_space.
|
||||
|
||||
## Input Sanitization
|
||||
|
||||
In order not to spread scripts, vulnerabilities, and glitchy HTML all over the place, GoToSocial performs the following types of input sanitization:
|
||||
|
|
|
@ -415,6 +415,61 @@ instance-deliver-to-shared-inboxes: true
|
|||
# Default: false
|
||||
instance-inject-mastodon-version: false
|
||||
|
||||
# String. 24hr time of day formatted as hh:mm.
|
||||
# Examples: ["14:30", "00:00", "04:00"]
|
||||
# Default: "23:00" (11pm).
|
||||
instance-subscriptions-process-from: "23:00"
|
||||
|
||||
# Duration. Period between subscription updates.
|
||||
# Examples: ["24h", "72h", "12h"]
|
||||
# Default: "24h" (once per day).
|
||||
instance-subscriptions-process-every: "24h"
|
||||
|
||||
# String. Allows you to customize if and how stats are served to
|
||||
# crawlers at the /api/v1|v2/instance and /nodeinfo endpoints.
|
||||
#
|
||||
# Note that no matter what you set below, the /api/v1|v2/instance
|
||||
# endpoints will not be allowed by robots.txt, as these are client
|
||||
# API endpoints.
|
||||
#
|
||||
# "" / empty string (default mode): Serve accurate stats at instance
|
||||
# and nodeinfo endpoints, and DISALLOW crawlers from crawling
|
||||
# those endpoints in robots.txt. This mode is equivalent to politely
|
||||
# asking crawlers not to crawl, but there's no guarantee they will obey,
|
||||
# as unfortunately many crawlers don't even check robots.txt.
|
||||
#
|
||||
# "zero": Serve zeroed-out stats at instance and nodeinfo endpoints,
|
||||
# and DISALLOW crawlers from crawling those endpoints in robots.txt.
|
||||
# This mode prevents even ill-behaved crawlers from gathering stats
|
||||
# about your instance, as all gathered values will be 0. This is the
|
||||
# safest way of preserving your instance's privacy in terms of stats.
|
||||
#
|
||||
# "serve": Serve accurate stats at instance and nodeinfo endpoints,
|
||||
# and ALLOW crawlers to crawl those endpoints. This mode is useful
|
||||
# if you want to contribute to fediverse statistics collection projects.
|
||||
#
|
||||
# "baffle": Serve randomized, preposterous stats at instance and nodeinfo
|
||||
# endpoints, and DISALLOW crawlers from crawling those endpoints in robots.txt.
|
||||
# This mode can be useful to annoy crawlers that don't respect robots.txt.
|
||||
# Warning that this may draw the ire of crawler implementers who don't
|
||||
# respect robots.txt, and may therefore put a target on your instance.
|
||||
#
|
||||
# Options: ["", "zero", "serve", "baffle"]
|
||||
# Default: ""
|
||||
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.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Options: [true, false]
|
||||
# Default: true
|
||||
instance-allow-backdating-statuses: true
|
||||
|
||||
###########################
|
||||
##### ACCOUNTS CONFIG #####
|
||||
|
@ -433,6 +488,28 @@ accounts-registration-open: false
|
|||
# Default: true
|
||||
accounts-reason-required: true
|
||||
|
||||
# Int. Number of approved sign-ups allowed within
|
||||
# 24hrs before new account registration is closed.
|
||||
#
|
||||
# Leaving this count at the default essentially limits
|
||||
# your instance to growing by 10 accounts per day.
|
||||
#
|
||||
# Setting this number to 0 or less removes the limit.
|
||||
#
|
||||
# Default: 10
|
||||
accounts-registration-daily-limit: 10
|
||||
|
||||
# Int. Number of new account sign-ups allowed in the pending
|
||||
# approval queue before new account registration is closed.
|
||||
#
|
||||
# This can be used to essentially "throttle" the sign-up
|
||||
# queue to prevent instance admins becoming overwhelmed.
|
||||
#
|
||||
# Setting this number to 0 or less removes the limit.
|
||||
#
|
||||
# Default: 20
|
||||
accounts-registration-backlog-limit: 20
|
||||
|
||||
# Bool. Allow accounts on this instance to set custom CSS for their profile pages and statuses.
|
||||
# Enabling this setting will allow accounts to upload custom CSS via the /user settings page,
|
||||
# which will then be rendered on the web view of the account's profile and statuses.
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
version: "3.3"
|
||||
|
||||
services:
|
||||
gotosocial:
|
||||
image: superseriousbusiness/gotosocial:latest
|
||||
|
@ -24,7 +22,7 @@ services:
|
|||
# Wazero compilation cache will be stored.
|
||||
GTS_WAZERO_COMPILATION_CACHE: /gotosocial/.cache
|
||||
## For reverse proxy setups:
|
||||
# GTS_TRUSTED_PROXIES: "172.x.x.x"
|
||||
GTS_TRUSTED_PROXIES: "172.18.0.1/16"
|
||||
## Set the timezone of your server:
|
||||
#TZ: UTC
|
||||
ports:
|
||||
|
@ -47,3 +45,6 @@ networks:
|
|||
gotosocial:
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: "172.18.0.0/16"
|
||||
gateway: "172.18.0.1"
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
version: "3"
|
||||
services:
|
||||
tempo:
|
||||
image: docker.io/grafana/tempo:2.1.1
|
||||
image: docker.io/grafana/tempo:latest
|
||||
command: [ "-config.file=/etc/tempo.yaml" ]
|
||||
volumes:
|
||||
- ./tempo.yaml:/etc/tempo.yaml
|
||||
- ./tempo-data:/tmp/tempo
|
||||
- ./tempo.yaml:/etc/tempo.yaml:Z
|
||||
ports:
|
||||
- "3200:3200" # tempo
|
||||
- "9095:9095" # tempo grpc
|
||||
- "4317:4317" # otlp grpc
|
||||
- "4318:4318" # otlp http
|
||||
|
||||
grafana:
|
||||
image: docker.io/grafana/grafana:9.5.2
|
||||
image: docker.io/grafana/grafana:latest
|
||||
volumes:
|
||||
- ./grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml
|
||||
- ./grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml:Z
|
||||
environment:
|
||||
- GF_AUTH_ANONYMOUS_ENABLED=true
|
||||
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
|
||||
|
|
|
@ -5,7 +5,10 @@ distributor:
|
|||
receivers:
|
||||
otlp:
|
||||
protocols:
|
||||
http:
|
||||
endpoint: '0.0.0.0:4318'
|
||||
grpc:
|
||||
endpoint: '0.0.0.0:4317'
|
||||
|
||||
ingester:
|
||||
max_block_duration: 5m
|
||||
|
|
145
go.mod
145
go.mod
|
@ -6,22 +6,7 @@ go 1.23
|
|||
replace github.com/go-swagger/go-swagger => github.com/superseriousbusiness/go-swagger v0.31.0-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.34.2-concurrency-workaround
|
||||
|
||||
// Below pin otel libraries to v1.29.0 until we can figure out issues
|
||||
replace go.opentelemetry.io/otel => go.opentelemetry.io/otel v1.29.0
|
||||
|
||||
replace go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc => go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0
|
||||
|
||||
replace go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp => go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0
|
||||
|
||||
replace go.opentelemetry.io/otel/metric => go.opentelemetry.io/otel/metric v1.29.0
|
||||
|
||||
replace go.opentelemetry.io/otel/sdk => go.opentelemetry.io/otel/sdk v1.29.0
|
||||
|
||||
replace go.opentelemetry.io/otel/sdk/metric => go.opentelemetry.io/otel/sdk/metric v1.29.0
|
||||
|
||||
replace go.opentelemetry.io/otel/trace => go.opentelemetry.io/otel/trace v1.29.0
|
||||
replace modernc.org/sqlite => gitlab.com/NyaaaWhatsUpDoc/sqlite v1.34.5-concurrency-workaround
|
||||
|
||||
require (
|
||||
codeberg.org/gruf/go-bytes v1.0.2
|
||||
|
@ -31,7 +16,7 @@ require (
|
|||
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.1
|
||||
codeberg.org/gruf/go-ffmpreg v0.6.5
|
||||
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
|
||||
codeberg.org/gruf/go-kv v1.6.5
|
||||
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f
|
||||
|
@ -43,12 +28,13 @@ require (
|
|||
codeberg.org/gruf/go-structr v0.8.11
|
||||
codeberg.org/superseriousbusiness/exif-terminator v0.9.1
|
||||
github.com/DmitriyVTitov/size v1.5.0
|
||||
github.com/KimMachineGun/automemlimit v0.6.1
|
||||
github.com/KimMachineGun/automemlimit v0.7.0
|
||||
github.com/SherClockHolmes/webpush-go v1.4.0
|
||||
github.com/buckket/go-blurhash v1.1.0
|
||||
github.com/coreos/go-oidc/v3 v3.11.0
|
||||
github.com/gin-contrib/cors v1.7.2
|
||||
github.com/gin-contrib/gzip v1.0.1
|
||||
github.com/gin-contrib/sessions v1.0.1
|
||||
github.com/coreos/go-oidc/v3 v3.12.0
|
||||
github.com/gin-contrib/cors v1.7.3
|
||||
github.com/gin-contrib/gzip v1.2.2
|
||||
github.com/gin-contrib/sessions v1.0.2
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/go-playground/form/v4 v4.2.1
|
||||
github.com/go-swagger/go-swagger v0.31.0
|
||||
|
@ -56,50 +42,53 @@ require (
|
|||
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.1
|
||||
github.com/jackc/pgx/v5 v5.7.2
|
||||
github.com/k3a/html2text v1.2.1
|
||||
github.com/microcosm-cc/bluemonday v1.0.27
|
||||
github.com/miekg/dns v1.1.62
|
||||
github.com/minio/minio-go/v7 v7.0.81
|
||||
github.com/miekg/dns v1.1.63
|
||||
github.com/minio/minio-go/v7 v7.0.85
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/ncruces/go-sqlite3 v0.20.3
|
||||
github.com/ncruces/go-sqlite3 v0.23.0
|
||||
github.com/oklog/ulid v1.3.1
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
github.com/rivo/uniseg v0.4.7
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/superseriousbusiness/activity v1.9.0-gts
|
||||
github.com/superseriousbusiness/activity v1.10.0-gts
|
||||
github.com/superseriousbusiness/httpsig v1.2.0-SSB
|
||||
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8
|
||||
github.com/tdewolff/minify/v2 v2.21.2
|
||||
github.com/tdewolff/minify/v2 v2.21.3
|
||||
github.com/technologize/otel-go-contrib v1.1.1
|
||||
github.com/temoto/robotstxt v1.1.2
|
||||
github.com/tetratelabs/wazero v1.8.2
|
||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
||||
github.com/ulule/limiter/v3 v3.11.2
|
||||
github.com/uptrace/bun v1.2.6
|
||||
github.com/uptrace/bun/dialect/pgdialect v1.2.6
|
||||
github.com/uptrace/bun/dialect/sqlitedialect v1.2.6
|
||||
github.com/uptrace/bun/extra/bunotel v1.2.6
|
||||
github.com/uptrace/bun v1.2.9
|
||||
github.com/uptrace/bun/dialect/pgdialect v1.2.9
|
||||
github.com/uptrace/bun/dialect/sqlitedialect v1.2.9
|
||||
github.com/uptrace/bun/extra/bunotel v1.2.9
|
||||
github.com/wagslane/go-password-validator v0.3.0
|
||||
github.com/yuin/goldmark v1.7.8
|
||||
go.opentelemetry.io/otel v1.32.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.51.0
|
||||
go.opentelemetry.io/otel/metric v1.32.0
|
||||
go.opentelemetry.io/otel/sdk v1.32.0
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0
|
||||
go.opentelemetry.io/otel/trace v1.32.0
|
||||
go.opentelemetry.io/otel v1.34.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.56.0
|
||||
go.opentelemetry.io/otel/metric v1.34.0
|
||||
go.opentelemetry.io/otel/sdk v1.34.0
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0
|
||||
go.opentelemetry.io/otel/trace v1.34.0
|
||||
go.uber.org/automaxprocs v1.6.0
|
||||
golang.org/x/crypto v0.29.0
|
||||
golang.org/x/image v0.22.0
|
||||
golang.org/x/net v0.31.0
|
||||
golang.org/x/oauth2 v0.24.0
|
||||
golang.org/x/text v0.20.0
|
||||
golang.org/x/crypto v0.33.0
|
||||
golang.org/x/image v0.24.0
|
||||
golang.org/x/net v0.34.0
|
||||
golang.org/x/oauth2 v0.26.0
|
||||
golang.org/x/sys v0.30.0
|
||||
golang.org/x/text v0.22.0
|
||||
gopkg.in/mcuadros/go-syslog.v2 v2.3.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
modernc.org/sqlite v0.0.0-00010101000000-000000000000
|
||||
mvdan.cc/xurls/v2 v2.5.0
|
||||
mvdan.cc/xurls/v2 v2.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -111,20 +100,13 @@ require (
|
|||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/bytedance/sonic v1.11.6 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/bytedance/sonic v1.12.7 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.2 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cilium/ebpf v0.9.1 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/containerd/cgroups/v3 v3.0.1 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b // indirect
|
||||
github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb // indirect
|
||||
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
|
||||
|
@ -132,9 +114,9 @@ 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.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // 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/go-errors/errors v1.1.1 // indirect
|
||||
github.com/go-fed/httpsig v1.1.0 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
|
@ -154,19 +136,18 @@ require (
|
|||
github.com/go-openapi/validate v0.24.0 // indirect
|
||||
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.20.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.24.0 // indirect
|
||||
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/godbus/dbus/v5 v5.0.4 // indirect
|
||||
github.com/goccy/go-json v0.10.4 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 // 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.2.2 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/huandu/xstrings v1.4.0 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
|
@ -179,7 +160,7 @@ require (
|
|||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 // 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
|
||||
|
@ -194,23 +175,21 @@ require (
|
|||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/ncruces/julianday v1.0.0 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.0.2 // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // 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.59.1 // indirect
|
||||
github.com/prometheus/common v0.61.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.0 // 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.12.0 // 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.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
|
@ -226,27 +205,23 @@ require (
|
|||
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
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41 // indirect
|
||||
go.mongodb.org/mongo-driver v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/arch v0.13.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/sync v0.9.0 // indirect
|
||||
golang.org/x/sys v0.27.0 // indirect
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||
google.golang.org/grpc v1.66.1 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/sync v0.11.0 // indirect
|
||||
golang.org/x/tools v0.28.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect
|
||||
google.golang.org/grpc v1.69.4 // indirect
|
||||
google.golang.org/protobuf v1.36.3 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
|
||||
modernc.org/libc v1.55.3 // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
modernc.org/memory v1.8.0 // indirect
|
||||
modernc.org/strutil v1.2.0 // indirect
|
||||
modernc.org/token v1.1.0 // indirect
|
||||
)
|
||||
|
|
303
go.sum
generated
303
go.sum
generated
|
@ -46,8 +46,8 @@ 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.1 h1:HitxOKPhbwARV469h6jY9a3IlROiwAN6QTbTxLRBnC8=
|
||||
codeberg.org/gruf/go-ffmpreg v0.6.1/go.mod h1:HQmEaBF83rHOt2Jo1yJv9D0JApoSLFtVR9Uzu7aVglk=
|
||||
codeberg.org/gruf/go-ffmpreg v0.6.5 h1:Ai7UnFfBFyz65m54/OlhCs++cFnepS4X++oV5VtyeQU=
|
||||
codeberg.org/gruf/go-ffmpreg v0.6.5/go.mod h1:HQmEaBF83rHOt2Jo1yJv9D0JApoSLFtVR9Uzu7aVglk=
|
||||
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=
|
||||
|
@ -79,8 +79,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
|||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
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.6.1 h1:ILa9j1onAAMadBsyyUJv5cack8Y1WT26yLj/V+ulKp8=
|
||||
github.com/KimMachineGun/automemlimit v0.6.1/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY=
|
||||
github.com/KimMachineGun/automemlimit v0.7.0 h1:7G06p/dMSf7G8E6oq+f2uOPuVncFyIlDI/pBWK49u88=
|
||||
github.com/KimMachineGun/automemlimit v0.7.0/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=
|
||||
|
@ -88,6 +88,8 @@ github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0
|
|||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
|
||||
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/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.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
|
@ -97,18 +99,15 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d
|
|||
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=
|
||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/buckket/go-blurhash v1.1.0 h1:X5M6r0LIvwdvKiUtiNcRL2YlmOfMzYobI3VCKCZc9Do=
|
||||
github.com/buckket/go-blurhash v1.1.0/go.mod h1:aT2iqo5W9vu9GpyoLErKfTHwgODsZp3bQfXjXJUxNb8=
|
||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||
github.com/bytedance/sonic v1.12.7 h1:CQU8pxOy9HToxhndH0Kx/S1qU/CuS9GnKYrGioDcU1Q=
|
||||
github.com/bytedance/sonic v1.12.7/go.mod h1:tnbal4mxOMju17EGfknm2XyYcpyCnIROYOEYuemj13I=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic/loader v0.2.2 h1:jxAJuN9fOot/cyz5Q6dUuMJF5OqQ6+5GfA8FjjQ0R4o=
|
||||
github.com/bytedance/sonic/loader v0.2.2/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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
|
@ -117,30 +116,21 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
|||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cilium/ebpf v0.9.1 h1:64sn2K3UKw8NbP/blsixRpF3nXuyhz/VjRlRzvlBRu4=
|
||||
github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
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/containerd/cgroups/v3 v3.0.1 h1:4hfGvu8rfGIwVIDd+nLzn/B9ZXx4BcCjzt5ToenJRaE=
|
||||
github.com/containerd/cgroups/v3 v3.0.1/go.mod h1:/vtwk1VXrtoa5AaZLkypuOJgA/6DyPMZHJPGQNtlHnw=
|
||||
github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI=
|
||||
github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/go-oidc/v3 v3.12.0 h1:sJk+8G2qq94rDI6ehZ71Bol3oUHy63qNYmkiSjrc/Jo=
|
||||
github.com/coreos/go-oidc/v3 v3.12.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
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=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8=
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20210428042052-dca55bf8ca15/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
|
||||
|
@ -172,22 +162,22 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
|
|||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
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/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.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||
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.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw=
|
||||
github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E=
|
||||
github.com/gin-contrib/gzip v1.0.1 h1:HQ8ENHODeLY7a4g1Au/46Z92bdGFl74OhxcZble9WJE=
|
||||
github.com/gin-contrib/gzip v1.0.1/go.mod h1:njt428fdUNRvjuJf16tZMYZ2Yl+WQB53X5wmhDwXvC4=
|
||||
github.com/gin-contrib/sessions v1.0.1 h1:3hsJyNs7v7N8OtelFmYXFrulAf6zSR7nW/putcPEHxI=
|
||||
github.com/gin-contrib/sessions v1.0.1/go.mod h1:ouxSFM24/OgIud5MJYQJLpy6AwxQ5EYO9yLhbtObGkM=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-contrib/cors v1.7.3 h1:hV+a5xp8hwJoTw7OY+a70FsL8JkVVFTXw9EcfrYUdns=
|
||||
github.com/gin-contrib/cors v1.7.3/go.mod h1:M3bcKZhxzsvI+rlRSkkxHyljJt1ESd93COUvemZ79j4=
|
||||
github.com/gin-contrib/gzip v1.2.2 h1:iUU/EYCM8ENfkjmZaVrxbjF/ZC267Iqv5S0MMCMEliI=
|
||||
github.com/gin-contrib/gzip v1.2.2/go.mod h1:C1a5cacjlDsS20cKnHlZRCPUu57D3qH6B2pV0rl+Y/s=
|
||||
github.com/gin-contrib/sessions v1.0.2 h1:UaIjUvTH1cMeOdj3in6dl+Xb6It8RiKRF9Z1anbUyCA=
|
||||
github.com/gin-contrib/sessions v1.0.2/go.mod h1:KxKxWqWP5LJVDCInulOl4WbLzK2KSPlLesfZ66wRvMs=
|
||||
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/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
|
@ -239,20 +229,20 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
|||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg=
|
||||
github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
||||
github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0=
|
||||
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-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/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
|
||||
github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
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 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
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=
|
||||
|
@ -284,6 +274,8 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
|
|||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
|
@ -334,12 +326,10 @@ github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8L
|
|||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
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.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
|
@ -358,8 +348,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.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
|
||||
github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
|
||||
github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI=
|
||||
github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
|
||||
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=
|
||||
|
@ -385,8 +375,8 @@ github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IX
|
|||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
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.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
|
@ -409,12 +399,12 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
|||
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.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
|
||||
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
|
||||
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
|
||||
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
|
||||
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.81 h1:SzhMN0TQ6T/xSBu6Nvw3M5M8voM+Ht8RH3hE8S7zxaA=
|
||||
github.com/minio/minio-go/v7 v7.0.81/go.mod h1:84gmIilaX4zcvAWWzJ5Z1WI5axN+hAbM5w25xf8xvC0=
|
||||
github.com/minio/minio-go/v7 v7.0.85 h1:9psTLS/NTvC3MWoyjhjXpwcKoNbkongaCSF3PNpSuXo=
|
||||
github.com/minio/minio-go/v7 v7.0.85/go.mod h1:57YXpvc5l3rjPdhqNrDsvVlY0qPI6UTk1bflAe+9doY=
|
||||
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=
|
||||
|
@ -434,8 +424,8 @@ 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.20.3 h1:+4G4uEqOeusF0yRuQVUl9fuoEebUolwQSnBUjYBLYIw=
|
||||
github.com/ncruces/go-sqlite3 v0.20.3/go.mod h1:ojLIAB243gtz68Eo283Ps+k9PyR3dvzS+9/RgId4+AA=
|
||||
github.com/ncruces/go-sqlite3 v0.23.0 h1:90j/ar8Ywu2AtsfDl5WhO9sgP/rNk76BcKGIzAHO8AQ=
|
||||
github.com/ncruces/go-sqlite3 v0.23.0/go.mod h1:gq2nriHSczOs11SqGW5+0X+SgLdkdj4K+j4F/AhQ+8g=
|
||||
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=
|
||||
|
@ -448,12 +438,10 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
|
|||
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0=
|
||||
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
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.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
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/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=
|
||||
|
@ -467,20 +455,22 @@ github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/j
|
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
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.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJoX0=
|
||||
github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0=
|
||||
github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ=
|
||||
github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s=
|
||||
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/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.0 h1:i+cMcpEDY1BkNm7lPDkCtE4oElsYLn+EKF8kAu2vXT4=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b h1:aUNXCGgukb4gtY99imuIeoh8Vr0GSwAlYxPAhqZrpFc=
|
||||
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a h1:w3tdWGKbLGBPtR/8/oO74W6hmz0qE5q0z9aqSAewaaM=
|
||||
github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a/go.mod h1:S8kfXMp+yh77OxPD4fdM6YUknrZpQxLhvxzS4gDHENY=
|
||||
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=
|
||||
|
@ -494,8 +484,6 @@ github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX
|
|||
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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
|
@ -527,13 +515,12 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
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.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
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/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/superseriousbusiness/activity v1.9.0-gts h1:qWMDeiGdnVi+XG7CfuM7ET87qe9adousU6utWItBX/o=
|
||||
github.com/superseriousbusiness/activity v1.9.0-gts/go.mod h1:9l74ZCv8zw07vipNMzahq8oQZt2xPaJZ+L+gLicQntQ=
|
||||
github.com/superseriousbusiness/activity v1.10.0-gts h1:uYIHU0/jDpLxj0lA3Jg24lM8p3X/Vb3J7hn3yQJR+C8=
|
||||
github.com/superseriousbusiness/activity v1.10.0-gts/go.mod h1:9l74ZCv8zw07vipNMzahq8oQZt2xPaJZ+L+gLicQntQ=
|
||||
github.com/superseriousbusiness/go-jpeg-image-structure/v2 v2.0.0-20220321154430-d89a106fdabe h1:ksl2oCx/Qo8sNDc3Grb8WGKBM9nkvhCm25uvlT86azE=
|
||||
github.com/superseriousbusiness/go-jpeg-image-structure/v2 v2.0.0-20220321154430-d89a106fdabe/go.mod h1:gH4P6gN1V+wmIw5o97KGaa1RgXB/tVpC2UNzijhg3E4=
|
||||
github.com/superseriousbusiness/go-png-image-structure/v2 v2.0.1-SSB h1:8psprYSK1KdOSH7yQ4PbJq0YYaGQY+gzdW/B0ExDb/8=
|
||||
|
@ -544,8 +531,8 @@ github.com/superseriousbusiness/httpsig v1.2.0-SSB h1:BinBGKbf2LSuVT5+MuH0XynHN9
|
|||
github.com/superseriousbusiness/httpsig v1.2.0-SSB/go.mod h1:+rxfATjFaDoDIVaJOTSP0gj6UrbicaYPEptvCLC9F28=
|
||||
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8 h1:nTIhuP157oOFcscuoK1kCme1xTeGIzztSw70lX9NrDQ=
|
||||
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8/go.mod h1:uYC/W92oVRJ49Vh1GcvTqpeFqHi+Ovrl2sMllQWRAEo=
|
||||
github.com/tdewolff/minify/v2 v2.21.2 h1:VfTvmGVtBYhMTlUAeHtXM7XOsW0JT/6uMwUPPqgUs9k=
|
||||
github.com/tdewolff/minify/v2 v2.21.2/go.mod h1:Olje3eHdBnrMjINKffDsil/3NV98Iv7MhWf7556WQVg=
|
||||
github.com/tdewolff/minify/v2 v2.21.3 h1:KmhKNGrN/dGcvb2WDdB5yA49bo37s+hcD8RiF+lioV8=
|
||||
github.com/tdewolff/minify/v2 v2.21.3/go.mod h1:iGxHaGiONAnsYuo8CRyf8iPUcqRJVB/RhtEcTpqS7xw=
|
||||
github.com/tdewolff/parse/v2 v2.7.19 h1:7Ljh26yj+gdLFEq/7q9LT4SYyKtwQX4ocNrj45UCePg=
|
||||
github.com/tdewolff/parse/v2 v2.7.19/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
|
||||
github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||
|
@ -553,6 +540,8 @@ github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03
|
|||
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/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.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4=
|
||||
github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
|
||||
github.com/tidwall/btree v0.0.0-20191029221954-400434d76274 h1:G6Z6HvJuPjG6XfNGi/feOATzeJrfgTNJY+rGrHbA04E=
|
||||
|
@ -585,14 +574,14 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
|
|||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
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.6 h1:lyGBQAhNiClchb97HA2cBnDeRxwTRLhSIgiFPXVisV8=
|
||||
github.com/uptrace/bun v1.2.6/go.mod h1:xMgnVFf+/5xsrFBU34HjDJmzZnXbVuNEt/Ih56I8qBU=
|
||||
github.com/uptrace/bun/dialect/pgdialect v1.2.6 h1:iNd1YLx619K+sZK+dRcWPzluurXYK1QwIkp9FEfNB/8=
|
||||
github.com/uptrace/bun/dialect/pgdialect v1.2.6/go.mod h1:OL7d3qZLxKYP8kxNhMg3IheN1pDR3UScGjoUP+ivxJQ=
|
||||
github.com/uptrace/bun/dialect/sqlitedialect v1.2.6 h1:p8vA39kR9Ypw0so+gUhFhd8NOufx3MzvoxJeUpwieQU=
|
||||
github.com/uptrace/bun/dialect/sqlitedialect v1.2.6/go.mod h1:sdGy8eCv9WVGDrPhagE9i7FASeyj3BFkHzkRMF/qK3w=
|
||||
github.com/uptrace/bun/extra/bunotel v1.2.6 h1:6m90acv9hsDuTYRo3oiKCWMatGPmi+feKAx8Y/GPj9A=
|
||||
github.com/uptrace/bun/extra/bunotel v1.2.6/go.mod h1:QGqnFNJ2H88juh7DmgdPJZVN9bSTpj7UaGllSO9JDKk=
|
||||
github.com/uptrace/bun v1.2.9 h1:OOt2DlIcRUMSZPr6iXDFg/LaQd59kOxbAjpIVHddKRs=
|
||||
github.com/uptrace/bun v1.2.9/go.mod h1:r2ZaaGs9Ru5bpGTr8GQfp8jp+TlCav9grYCPOu2CJSg=
|
||||
github.com/uptrace/bun/dialect/pgdialect v1.2.9 h1:caf5uFbOGiXvadV6pA5gn87k0awFFxL1kuuY3SpxnWk=
|
||||
github.com/uptrace/bun/dialect/pgdialect v1.2.9/go.mod h1:m7L9JtOp/Lt8HccET70ULxplMweE/u0S9lNUSxz2duo=
|
||||
github.com/uptrace/bun/dialect/sqlitedialect v1.2.9 h1:HLzGWXBh07sT8zhVPy6veYbbGrAtYq0KzyRHXBj+GjA=
|
||||
github.com/uptrace/bun/dialect/sqlitedialect v1.2.9/go.mod h1:dUR+ecoCWA0FIa9vhQVRnGtYYPpuCLJoEEtX9E1aiBU=
|
||||
github.com/uptrace/bun/extra/bunotel v1.2.9 h1:BGGrBga+iVL78SGiMpLt2N9MAKvrG3f8wLk8zCLwFJg=
|
||||
github.com/uptrace/bun/extra/bunotel v1.2.9/go.mod h1:6dVl5Ko6xOhuoqUPWHpfFrntBDwmOnq0OMiR/SGwAC8=
|
||||
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=
|
||||
|
@ -607,8 +596,6 @@ github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAh
|
|||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||
github.com/wagslane/go-password-validator v0.3.0 h1:vfxOPzGHkz5S146HDpavl0cw1DSVP061Ry2PX0/ON6I=
|
||||
github.com/wagslane/go-password-validator v0.3.0/go.mod h1:TI1XJ6T5fRdRnHqHt14pvy1tNVnrwe7m3/f1f2fDphQ=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41 h1:rnB8ZLMeAr3VcqjfRkAm27qb8y6zFKNfuHvy1Gfe7KI=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41/go.mod h1:DbzwytT4g/odXquuOCqroKvtxxldI4nb3nuesHF/Exo=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||
|
@ -630,8 +617,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
|
||||
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
gitlab.com/NyaaaWhatsUpDoc/sqlite v1.34.2-concurrency-workaround h1:Z/9vgdPNZm8ZDANnIJ7ZGeYKJ5biqPY1OQbN+DLCtec=
|
||||
gitlab.com/NyaaaWhatsUpDoc/sqlite v1.34.2-concurrency-workaround/go.mod h1:dnR723UrTtjKpoHCAMN0Q/gZ9MT4r+iRvIBb9umWFkU=
|
||||
gitlab.com/NyaaaWhatsUpDoc/sqlite v1.34.5-concurrency-workaround h1:BLmmUkkZ2KiS8k2lePZRQo7Z5puFrfxuFq9BrJQmS9o=
|
||||
gitlab.com/NyaaaWhatsUpDoc/sqlite v1.34.5-concurrency-workaround/go.mod h1:YLuNmX9NKs8wRNK2ko1LW1NGYcc9FkBO69JOt1AR9JE=
|
||||
go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
|
||||
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
|
@ -639,35 +626,36 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
|||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
|
||||
go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 h1:JAv0Jwtl01UFiyWZEMiJZBiTlv5A50zNs8lsthXqIio=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0/go.mod h1:QNKLmUEAq2QUbPQUfvw4fmv0bgbK7UlOSFCnXyfvSNc=
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.51.0 h1:G7uexXb/K3T+T9fNLCCKncweEtNEBMTO+46hKX5EdKw=
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.51.0/go.mod h1:v0mFe5Kk7woIh938mrZBJBmENYquyA0IICrlYm4Y0t4=
|
||||
go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
|
||||
go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
|
||||
go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
|
||||
go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.29.0 h1:K2CfmJohnRgvZ9UAj2/FhIf/okdWcNdBwe1m8xFXiSY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ=
|
||||
go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
|
||||
go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
||||
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.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 h1:BEj3SPM81McUZHYjRS5pEgNgnmzGJ5tRpU5krWnV8Bs=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4=
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.56.0 h1:GnCIi0QyG0yy2MrJLzVrIM7laaJstj//flf1zEJCG+E=
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.56.0/go.mod h1:JQcVZtbIIPM+7SWBB+T6FK+xunlyidwLp++fN0sUaOk=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
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.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.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA=
|
||||
golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
@ -675,8 +663,12 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
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=
|
||||
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
|
||||
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
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.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -691,8 +683,8 @@ golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUF
|
|||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.22.0 h1:UtK5yLUzilVrkjMAZAZ34DXGpASN8i8pj8g+O+yd10g=
|
||||
golang.org/x/image v0.22.0/go.mod h1:9hPFhljd4zZ1GNSIZJ49sqbp45GKK9t6w+iXvGqZUz4=
|
||||
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
|
||||
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
@ -712,8 +704,12 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
|
|||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
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.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -746,16 +742,21 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
|
|||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
|
||||
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
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.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
|
||||
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE=
|
||||
golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -765,8 +766,13 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -802,18 +808,29 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
|
||||
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
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.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -821,8 +838,14 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|||
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=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
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.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -868,8 +891,11 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc
|
|||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
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.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -925,10 +951,10 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc
|
|||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
|
@ -941,8 +967,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
|
|||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM=
|
||||
google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
||||
google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=
|
||||
google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
@ -953,8 +979,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
|||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=
|
||||
google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -992,8 +1018,6 @@ modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
|||
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
|
||||
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
|
||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
|
||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
|
||||
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
|
||||
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
|
||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||
|
@ -1008,10 +1032,9 @@ modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
|||
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
mvdan.cc/xurls/v2 v2.5.0 h1:lyBNOm8Wo71UknhUs4QTFUNNMyxy2JEIaKKo0RWOh+8=
|
||||
mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE=
|
||||
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=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
|
@ -23,11 +23,12 @@
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtscontext"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/state"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/workers"
|
||||
)
|
||||
|
||||
func errActionConflict(action *gtsmodel.AdminAction) gtserror.WithCode {
|
||||
|
@ -42,15 +43,34 @@ func errActionConflict(action *gtsmodel.AdminAction) gtserror.WithCode {
|
|||
}
|
||||
|
||||
type Actions struct {
|
||||
r map[string]*gtsmodel.AdminAction
|
||||
state *state.State
|
||||
// Map of running actions.
|
||||
running map[string]*gtsmodel.AdminAction
|
||||
|
||||
// Not embedded struct,
|
||||
// to shield from access
|
||||
// by outside packages.
|
||||
// Lock for running admin actions.
|
||||
//
|
||||
// Not embedded struct, to shield
|
||||
// from access by outside packages.
|
||||
m sync.Mutex
|
||||
|
||||
// DB for storing, updating,
|
||||
// deleting admin actions etc.
|
||||
db db.DB
|
||||
|
||||
// Workers for queuing
|
||||
// admin action side effects.
|
||||
workers *workers.Workers
|
||||
}
|
||||
|
||||
func New(db db.DB, workers *workers.Workers) *Actions {
|
||||
return &Actions{
|
||||
running: make(map[string]*gtsmodel.AdminAction),
|
||||
db: db,
|
||||
workers: workers,
|
||||
}
|
||||
}
|
||||
|
||||
type ActionF func(context.Context) gtserror.MultiError
|
||||
|
||||
// Run runs the given admin action by executing the supplied function.
|
||||
//
|
||||
// Run handles locking, action insertion and updating, so you don't have to!
|
||||
|
@ -62,10 +82,10 @@ type Actions struct {
|
|||
// will be updated on the provided admin action in the database.
|
||||
func (a *Actions) Run(
|
||||
ctx context.Context,
|
||||
action *gtsmodel.AdminAction,
|
||||
f func(context.Context) gtserror.MultiError,
|
||||
adminAction *gtsmodel.AdminAction,
|
||||
f ActionF,
|
||||
) gtserror.WithCode {
|
||||
actionKey := action.Key()
|
||||
actionKey := adminAction.Key()
|
||||
|
||||
// LOCK THE MAP HERE, since we're
|
||||
// going to do some operations on it.
|
||||
|
@ -73,7 +93,7 @@ func (a *Actions) Run(
|
|||
|
||||
// Bail if an action with
|
||||
// this key is already running.
|
||||
running, ok := a.r[actionKey]
|
||||
running, ok := a.running[actionKey]
|
||||
if ok {
|
||||
a.m.Unlock()
|
||||
return errActionConflict(running)
|
||||
|
@ -81,7 +101,7 @@ func (a *Actions) Run(
|
|||
|
||||
// Action with this key not
|
||||
// yet running, create it.
|
||||
if err := a.state.DB.PutAdminAction(ctx, action); err != nil {
|
||||
if err := a.db.PutAdminAction(ctx, adminAction); err != nil {
|
||||
err = gtserror.Newf("db error putting admin action %s: %w", actionKey, err)
|
||||
|
||||
// Don't store in map
|
||||
|
@ -92,7 +112,7 @@ func (a *Actions) Run(
|
|||
|
||||
// Action was inserted,
|
||||
// store in map.
|
||||
a.r[actionKey] = action
|
||||
a.running[actionKey] = adminAction
|
||||
|
||||
// UNLOCK THE MAP HERE, since
|
||||
// we're done modifying it for now.
|
||||
|
@ -104,22 +124,22 @@ func (a *Actions) Run(
|
|||
|
||||
// Run the thing and collect errors.
|
||||
if errs := f(ctx); errs != nil {
|
||||
action.Errors = make([]string, 0, len(errs))
|
||||
adminAction.Errors = make([]string, 0, len(errs))
|
||||
for _, err := range errs {
|
||||
action.Errors = append(action.Errors, err.Error())
|
||||
adminAction.Errors = append(adminAction.Errors, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Action is no longer running:
|
||||
// remove from running map.
|
||||
a.m.Lock()
|
||||
delete(a.r, actionKey)
|
||||
delete(a.running, actionKey)
|
||||
a.m.Unlock()
|
||||
|
||||
// Mark as completed in the db,
|
||||
// storing errors for later review.
|
||||
action.CompletedAt = time.Now()
|
||||
if err := a.state.DB.UpdateAdminAction(ctx, action, "completed_at", "errors"); err != nil {
|
||||
adminAction.CompletedAt = time.Now()
|
||||
if err := a.db.UpdateAdminAction(ctx, adminAction, "completed_at", "errors"); err != nil {
|
||||
log.Errorf(ctx, "db error marking action %s as completed: %q", actionKey, err)
|
||||
}
|
||||
}()
|
||||
|
@ -135,8 +155,8 @@ func (a *Actions) GetRunning() []*gtsmodel.AdminAction {
|
|||
defer a.m.Unlock()
|
||||
|
||||
// Assemble all currently running actions.
|
||||
running := make([]*gtsmodel.AdminAction, 0, len(a.r))
|
||||
for _, action := range a.r {
|
||||
running := make([]*gtsmodel.AdminAction, 0, len(a.running))
|
||||
for _, action := range a.running {
|
||||
running = append(running, action)
|
||||
}
|
||||
|
||||
|
@ -166,5 +186,5 @@ func (a *Actions) TotalRunning() int {
|
|||
a.m.Lock()
|
||||
defer a.m.Unlock()
|
||||
|
||||
return len(a.r)
|
||||
return len(a.running)
|
||||
}
|
|
@ -32,12 +32,26 @@
|
|||
"github.com/superseriousbusiness/gotosocial/testrig"
|
||||
)
|
||||
|
||||
const (
|
||||
rMediaPath = "../../testrig/media"
|
||||
rTemplatePath = "../../web/template"
|
||||
)
|
||||
|
||||
type ActionsTestSuite struct {
|
||||
AdminStandardTestSuite
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *ActionsTestSuite) SetupSuite() {
|
||||
testrig.InitTestConfig()
|
||||
testrig.InitTestLog()
|
||||
}
|
||||
|
||||
func (suite *ActionsTestSuite) TestActionOverlap() {
|
||||
ctx := context.Background()
|
||||
var (
|
||||
testStructs = testrig.SetupTestStructs(rMediaPath, rTemplatePath)
|
||||
ctx = context.Background()
|
||||
)
|
||||
defer testrig.TearDownTestStructs(testStructs)
|
||||
|
||||
// Suspend account.
|
||||
action1 := >smodel.AdminAction{
|
||||
|
@ -61,7 +75,7 @@ func (suite *ActionsTestSuite) TestActionOverlap() {
|
|||
key2 := action2.Key()
|
||||
suite.Equal("account/01H90S1CXQ97J9625C5YBXZWGT", key2)
|
||||
|
||||
errWithCode := suite.adminProcessor.Actions().Run(
|
||||
errWithCode := testStructs.State.AdminActions.Run(
|
||||
ctx,
|
||||
action1,
|
||||
func(ctx context.Context) gtserror.MultiError {
|
||||
|
@ -74,7 +88,7 @@ func(ctx context.Context) gtserror.MultiError {
|
|||
|
||||
// While first action is sleeping, try to
|
||||
// process another with the same key.
|
||||
errWithCode = suite.adminProcessor.Actions().Run(
|
||||
errWithCode = testStructs.State.AdminActions.Run(
|
||||
ctx,
|
||||
action2,
|
||||
func(ctx context.Context) gtserror.MultiError {
|
||||
|
@ -90,13 +104,13 @@ func(ctx context.Context) gtserror.MultiError {
|
|||
|
||||
// Wait for action to finish.
|
||||
if !testrig.WaitFor(func() bool {
|
||||
return suite.adminProcessor.Actions().TotalRunning() == 0
|
||||
return testStructs.State.AdminActions.TotalRunning() == 0
|
||||
}) {
|
||||
suite.FailNow("timed out waiting for admin action(s) to finish")
|
||||
}
|
||||
|
||||
// Try again.
|
||||
errWithCode = suite.adminProcessor.Actions().Run(
|
||||
errWithCode = testStructs.State.AdminActions.Run(
|
||||
ctx,
|
||||
action2,
|
||||
func(ctx context.Context) gtserror.MultiError {
|
||||
|
@ -107,14 +121,18 @@ func(ctx context.Context) gtserror.MultiError {
|
|||
|
||||
// Wait for action to finish.
|
||||
if !testrig.WaitFor(func() bool {
|
||||
return suite.adminProcessor.Actions().TotalRunning() == 0
|
||||
return testStructs.State.AdminActions.TotalRunning() == 0
|
||||
}) {
|
||||
suite.FailNow("timed out waiting for admin action(s) to finish")
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ActionsTestSuite) TestActionWithErrors() {
|
||||
ctx := context.Background()
|
||||
var (
|
||||
testStructs = testrig.SetupTestStructs(rMediaPath, rTemplatePath)
|
||||
ctx = context.Background()
|
||||
)
|
||||
defer testrig.TearDownTestStructs(testStructs)
|
||||
|
||||
// Suspend a domain.
|
||||
action := >smodel.AdminAction{
|
||||
|
@ -125,7 +143,7 @@ func (suite *ActionsTestSuite) TestActionWithErrors() {
|
|||
AccountID: "01H90S1ZZXP4N74H4A9RVW1MRP",
|
||||
}
|
||||
|
||||
errWithCode := suite.adminProcessor.Actions().Run(
|
||||
errWithCode := testStructs.State.AdminActions.Run(
|
||||
ctx,
|
||||
action,
|
||||
func(ctx context.Context) gtserror.MultiError {
|
||||
|
@ -140,13 +158,13 @@ func(ctx context.Context) gtserror.MultiError {
|
|||
|
||||
// Wait for action to finish.
|
||||
if !testrig.WaitFor(func() bool {
|
||||
return suite.adminProcessor.Actions().TotalRunning() == 0
|
||||
return testStructs.State.AdminActions.TotalRunning() == 0
|
||||
}) {
|
||||
suite.FailNow("timed out waiting for admin action(s) to finish")
|
||||
}
|
||||
|
||||
// Get action from the db.
|
||||
dbAction, err := suite.db.GetAdminAction(ctx, action.ID)
|
||||
dbAction, err := testStructs.State.DB.GetAdminAction(ctx, action.ID)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
51
internal/admin/domainkeys.go
Normal file
51
internal/admin/domainkeys.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
// 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 admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
)
|
||||
|
||||
func (a *Actions) DomainKeysExpireF(domain string) ActionF {
|
||||
return func(ctx context.Context) gtserror.MultiError {
|
||||
var (
|
||||
expiresAt = time.Now()
|
||||
errs gtserror.MultiError
|
||||
)
|
||||
|
||||
// For each account on this domain, expire
|
||||
// the public key and update the account.
|
||||
if err := a.rangeDomainAccounts(ctx, domain, func(account *gtsmodel.Account) {
|
||||
account.PublicKeyExpiresAt = expiresAt
|
||||
if err := a.db.UpdateAccount(ctx,
|
||||
account,
|
||||
"public_key_expires_at",
|
||||
); err != nil {
|
||||
errs.Appendf("db error updating account: %w", err)
|
||||
}
|
||||
}); err != nil {
|
||||
errs.Appendf("db error ranging through accounts: %w", err)
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
}
|
387
internal/admin/domainperms.go
Normal file
387
internal/admin/domainperms.go
Normal file
|
@ -0,0 +1,387 @@
|
|||
// 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 admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"codeberg.org/gruf/go-kv"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/messages"
|
||||
)
|
||||
|
||||
// Returns an AdminActionF for
|
||||
// domain allow side effects.
|
||||
func (a *Actions) DomainAllowF(
|
||||
actionID string,
|
||||
domainAllow *gtsmodel.DomainAllow,
|
||||
) ActionF {
|
||||
return func(ctx context.Context) gtserror.MultiError {
|
||||
l := log.
|
||||
WithContext(ctx).
|
||||
WithFields(kv.Fields{
|
||||
{"action", "allow"},
|
||||
{"actionID", actionID},
|
||||
{"domain", domainAllow.Domain},
|
||||
}...)
|
||||
|
||||
// Log start + finish.
|
||||
l.Info("processing side effects")
|
||||
errs := a.domainAllowSideEffects(ctx, domainAllow)
|
||||
l.Info("finished processing side effects")
|
||||
|
||||
return errs
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Actions) domainAllowSideEffects(
|
||||
ctx context.Context,
|
||||
allow *gtsmodel.DomainAllow,
|
||||
) gtserror.MultiError {
|
||||
if config.GetInstanceFederationMode() == config.InstanceFederationModeAllowlist {
|
||||
// We're running in allowlist mode,
|
||||
// so there are no side effects to
|
||||
// process here.
|
||||
return nil
|
||||
}
|
||||
|
||||
// We're running in blocklist mode or
|
||||
// some similar mode which necessitates
|
||||
// domain allow side effects if a block
|
||||
// was in place when the allow was created.
|
||||
//
|
||||
// So, check if there's a block.
|
||||
block, err := a.db.GetDomainBlock(ctx, allow.Domain)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
errs := gtserror.NewMultiError(1)
|
||||
errs.Appendf("db error getting domain block %s: %w", allow.Domain, err)
|
||||
return errs
|
||||
}
|
||||
|
||||
if block == nil {
|
||||
// No block?
|
||||
// No problem!
|
||||
return nil
|
||||
}
|
||||
|
||||
// There was a block, over which the new
|
||||
// allow ought to take precedence. To account
|
||||
// for this, just run side effects as though
|
||||
// the domain was being unblocked, while
|
||||
// leaving the existing block in place.
|
||||
//
|
||||
// Any accounts that were suspended by
|
||||
// the block will be unsuspended and be
|
||||
// able to interact with the instance again.
|
||||
return a.domainUnblockSideEffects(ctx, block)
|
||||
}
|
||||
|
||||
// Returns an AdminActionF for
|
||||
// domain unallow side effects.
|
||||
func (a *Actions) DomainUnallowF(
|
||||
actionID string,
|
||||
domainAllow *gtsmodel.DomainAllow,
|
||||
) ActionF {
|
||||
return func(ctx context.Context) gtserror.MultiError {
|
||||
l := log.
|
||||
WithContext(ctx).
|
||||
WithFields(kv.Fields{
|
||||
{"action", "unallow"},
|
||||
{"actionID", actionID},
|
||||
{"domain", domainAllow.Domain},
|
||||
}...)
|
||||
|
||||
// Log start + finish.
|
||||
l.Info("processing side effects")
|
||||
errs := a.domainUnallowSideEffects(ctx, domainAllow)
|
||||
l.Info("finished processing side effects")
|
||||
|
||||
return errs
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Actions) domainUnallowSideEffects(
|
||||
ctx context.Context,
|
||||
allow *gtsmodel.DomainAllow,
|
||||
) gtserror.MultiError {
|
||||
if config.GetInstanceFederationMode() == config.InstanceFederationModeAllowlist {
|
||||
// We're running in allowlist mode,
|
||||
// so there are no side effects to
|
||||
// process here.
|
||||
return nil
|
||||
}
|
||||
|
||||
// We're running in blocklist mode or
|
||||
// some similar mode which necessitates
|
||||
// domain allow side effects if a block
|
||||
// was in place when the allow was removed.
|
||||
//
|
||||
// So, check if there's a block.
|
||||
block, err := a.db.GetDomainBlock(ctx, allow.Domain)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
errs := gtserror.NewMultiError(1)
|
||||
errs.Appendf("db error getting domain block %s: %w", allow.Domain, err)
|
||||
return errs
|
||||
}
|
||||
|
||||
if block == nil {
|
||||
// No block?
|
||||
// No problem!
|
||||
return nil
|
||||
}
|
||||
|
||||
// There was a block, over which the previous
|
||||
// allow was taking precedence. Now that the
|
||||
// allow has been removed, we should put the
|
||||
// side effects of the block back in place.
|
||||
//
|
||||
// To do this, process the block side effects
|
||||
// again as though the block were freshly
|
||||
// created. This will mark all accounts from
|
||||
// the blocked domain as suspended, and clean
|
||||
// up their follows/following, media, etc.
|
||||
return a.domainBlockSideEffects(ctx, block)
|
||||
}
|
||||
|
||||
func (a *Actions) DomainBlockF(
|
||||
actionID string,
|
||||
domainBlock *gtsmodel.DomainBlock,
|
||||
) ActionF {
|
||||
return func(ctx context.Context) gtserror.MultiError {
|
||||
l := log.
|
||||
WithContext(ctx).
|
||||
WithFields(kv.Fields{
|
||||
{"action", "block"},
|
||||
{"actionID", actionID},
|
||||
{"domain", domainBlock.Domain},
|
||||
}...)
|
||||
|
||||
skip, err := a.skipBlockSideEffects(ctx, domainBlock.Domain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if skip != "" {
|
||||
l.Infof("skipping side effects: %s", skip)
|
||||
return nil
|
||||
}
|
||||
|
||||
l.Info("processing side effects")
|
||||
errs := a.domainBlockSideEffects(ctx, domainBlock)
|
||||
l.Info("finished processing side effects")
|
||||
|
||||
return errs
|
||||
}
|
||||
}
|
||||
|
||||
// domainBlockSideEffects processes the side effects of a domain block:
|
||||
//
|
||||
// 1. Strip most info away from the instance entry for the domain.
|
||||
// 2. Pass each account from the domain to the processor for deletion.
|
||||
//
|
||||
// It should be called asynchronously, since it can take a while when
|
||||
// there are many accounts present on the given domain.
|
||||
func (a *Actions) domainBlockSideEffects(
|
||||
ctx context.Context,
|
||||
block *gtsmodel.DomainBlock,
|
||||
) gtserror.MultiError {
|
||||
var errs gtserror.MultiError
|
||||
|
||||
// If we have an instance entry for this domain,
|
||||
// update it with the new block ID and clear all fields
|
||||
instance, err := a.db.GetInstance(ctx, block.Domain)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
errs.Appendf("db error getting instance %s: %w", block.Domain, err)
|
||||
return errs
|
||||
}
|
||||
|
||||
if instance != nil {
|
||||
// We had an entry for this domain.
|
||||
columns := stubbifyInstance(instance, block.ID)
|
||||
if err := a.db.UpdateInstance(ctx, instance, columns...); err != nil {
|
||||
errs.Appendf("db error updating instance: %w", err)
|
||||
return errs
|
||||
}
|
||||
}
|
||||
|
||||
// For each account that belongs to this domain,
|
||||
// process an account delete message to remove
|
||||
// that account's posts, media, etc.
|
||||
if err := a.rangeDomainAccounts(ctx, block.Domain, func(account *gtsmodel.Account) {
|
||||
if err := a.workers.Client.Process(ctx, &messages.FromClientAPI{
|
||||
APObjectType: ap.ActorPerson,
|
||||
APActivityType: ap.ActivityDelete,
|
||||
GTSModel: block,
|
||||
Origin: account,
|
||||
Target: account,
|
||||
}); err != nil {
|
||||
errs.Append(err)
|
||||
}
|
||||
}); err != nil {
|
||||
errs.Appendf("db error ranging through accounts: %w", err)
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
func (a *Actions) DomainUnblockF(
|
||||
actionID string,
|
||||
domainBlock *gtsmodel.DomainBlock,
|
||||
) ActionF {
|
||||
return func(ctx context.Context) gtserror.MultiError {
|
||||
l := log.
|
||||
WithContext(ctx).
|
||||
WithFields(kv.Fields{
|
||||
{"action", "unblock"},
|
||||
{"actionID", actionID},
|
||||
{"domain", domainBlock.Domain},
|
||||
}...)
|
||||
|
||||
l.Info("processing side effects")
|
||||
errs := a.domainUnblockSideEffects(ctx, domainBlock)
|
||||
l.Info("finished processing side effects")
|
||||
|
||||
return errs
|
||||
}
|
||||
}
|
||||
|
||||
// domainUnblockSideEffects processes the side effects of undoing a
|
||||
// domain block:
|
||||
//
|
||||
// 1. Mark instance entry as no longer suspended.
|
||||
// 2. Mark each account from the domain as no longer suspended, if the
|
||||
// suspension origin corresponds to the ID of the provided domain block.
|
||||
//
|
||||
// It should be called asynchronously, since it can take a while when
|
||||
// there are many accounts present on the given domain.
|
||||
func (a *Actions) domainUnblockSideEffects(
|
||||
ctx context.Context,
|
||||
block *gtsmodel.DomainBlock,
|
||||
) gtserror.MultiError {
|
||||
var errs gtserror.MultiError
|
||||
|
||||
// Update instance entry for this domain, if we have it.
|
||||
instance, err := a.db.GetInstance(ctx, block.Domain)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
errs.Appendf("db error getting instance %s: %w", block.Domain, err)
|
||||
}
|
||||
|
||||
if instance != nil {
|
||||
// We had an entry, update it to signal
|
||||
// that it's no longer suspended.
|
||||
instance.SuspendedAt = time.Time{}
|
||||
instance.DomainBlockID = ""
|
||||
if err := a.db.UpdateInstance(
|
||||
ctx,
|
||||
instance,
|
||||
"suspended_at",
|
||||
"domain_block_id",
|
||||
); err != nil {
|
||||
errs.Appendf("db error updating instance: %w", err)
|
||||
return errs
|
||||
}
|
||||
}
|
||||
|
||||
// Unsuspend all accounts whose suspension origin was this domain block.
|
||||
if err := a.rangeDomainAccounts(ctx, block.Domain, func(account *gtsmodel.Account) {
|
||||
if account.SuspensionOrigin == "" || account.SuspendedAt.IsZero() {
|
||||
// Account wasn't suspended, nothing to do.
|
||||
return
|
||||
}
|
||||
|
||||
if account.SuspensionOrigin != block.ID {
|
||||
// Account was suspended, but not by
|
||||
// this domain block, leave it alone.
|
||||
return
|
||||
}
|
||||
|
||||
// Account was suspended by this domain
|
||||
// block, mark it as unsuspended.
|
||||
account.SuspendedAt = time.Time{}
|
||||
account.SuspensionOrigin = ""
|
||||
|
||||
if err := a.db.UpdateAccount(
|
||||
ctx,
|
||||
account,
|
||||
"suspended_at",
|
||||
"suspension_origin",
|
||||
); err != nil {
|
||||
errs.Appendf("db error updating account %s: %w", account.Username, err)
|
||||
}
|
||||
}); err != nil {
|
||||
errs.Appendf("db error ranging through accounts: %w", err)
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// skipBlockSideEffects checks if side effects of block creation
|
||||
// should be skipped for the given domain, taking account of
|
||||
// instance federation mode, and existence of any allows
|
||||
// which ought to "shield" this domain from being blocked.
|
||||
//
|
||||
// If the caller should skip, the returned string will be non-zero
|
||||
// and will be set to a reason why side effects should be skipped.
|
||||
//
|
||||
// - blocklist mode + allow exists: "..." (skip)
|
||||
// - blocklist mode + no allow: "" (don't skip)
|
||||
// - allowlist mode + allow exists: "" (don't skip)
|
||||
// - allowlist mode + no allow: "" (don't skip)
|
||||
func (a *Actions) skipBlockSideEffects(
|
||||
ctx context.Context,
|
||||
domain string,
|
||||
) (string, gtserror.MultiError) {
|
||||
var (
|
||||
skip string // Assume "" (don't skip).
|
||||
errs gtserror.MultiError
|
||||
)
|
||||
|
||||
// Never skip block side effects in allowlist mode.
|
||||
fediMode := config.GetInstanceFederationMode()
|
||||
if fediMode == config.InstanceFederationModeAllowlist {
|
||||
return skip, errs
|
||||
}
|
||||
|
||||
// We know we're in blocklist mode.
|
||||
//
|
||||
// We want to skip domain block side
|
||||
// effects if an allow is already
|
||||
// in place which overrides the block.
|
||||
|
||||
// Check if an explicit allow exists for this domain.
|
||||
domainAllow, err := a.db.GetDomainAllow(ctx, domain)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
errs.Appendf("error getting domain allow: %w", err)
|
||||
return skip, errs
|
||||
}
|
||||
|
||||
if domainAllow != nil {
|
||||
skip = "running in blocklist mode, and an explicit allow exists for this domain"
|
||||
return skip, errs
|
||||
}
|
||||
|
||||
return skip, errs
|
||||
}
|
99
internal/admin/util.go
Normal file
99
internal/admin/util.go
Normal file
|
@ -0,0 +1,99 @@
|
|||
// 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 admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
)
|
||||
|
||||
// stubbifyInstance renders the given instance as a stub,
|
||||
// removing most information from it and marking it as
|
||||
// suspended.
|
||||
//
|
||||
// For caller's convenience, this function returns the db
|
||||
// names of all columns that are updated by it.
|
||||
func stubbifyInstance(instance *gtsmodel.Instance, domainBlockID string) []string {
|
||||
instance.Title = ""
|
||||
instance.SuspendedAt = time.Now()
|
||||
instance.DomainBlockID = domainBlockID
|
||||
instance.ShortDescription = ""
|
||||
instance.Description = ""
|
||||
instance.Terms = ""
|
||||
instance.ContactEmail = ""
|
||||
instance.ContactAccountUsername = ""
|
||||
instance.ContactAccountID = ""
|
||||
instance.Version = ""
|
||||
|
||||
return []string{
|
||||
"title",
|
||||
"suspended_at",
|
||||
"domain_block_id",
|
||||
"short_description",
|
||||
"description",
|
||||
"terms",
|
||||
"contact_email",
|
||||
"contact_account_username",
|
||||
"contact_account_id",
|
||||
"version",
|
||||
}
|
||||
}
|
||||
|
||||
// rangeDomainAccounts iterates through all accounts
|
||||
// originating from the given domain, and calls the
|
||||
// provided range function on each account.
|
||||
//
|
||||
// If an error is returned while selecting accounts,
|
||||
// the loop will stop and return the error.
|
||||
func (a *Actions) rangeDomainAccounts(
|
||||
ctx context.Context,
|
||||
domain string,
|
||||
rangeF func(*gtsmodel.Account),
|
||||
) error {
|
||||
var (
|
||||
limit = 50 // Limit selection to avoid spiking mem/cpu.
|
||||
maxID string // Start with empty string to select from top.
|
||||
)
|
||||
|
||||
for {
|
||||
// Get (next) page of accounts.
|
||||
accounts, err := a.db.GetInstanceAccounts(ctx, domain, maxID, limit)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
// Real db error.
|
||||
return gtserror.Newf("db error getting instance accounts: %w", err)
|
||||
}
|
||||
|
||||
if len(accounts) == 0 {
|
||||
// No accounts left, we're done.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set next max ID for paging down.
|
||||
maxID = accounts[len(accounts)-1].ID
|
||||
|
||||
// Call provided range function.
|
||||
for _, account := range accounts {
|
||||
rangeF(account)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,22 @@
|
|||
|
||||
package ap
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"github.com/superseriousbusiness/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)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return publicURI
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/activitystreams-vocabulary
|
||||
const (
|
||||
ActivityAccept = "Accept" // ActivityStreamsAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
"io"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/activity/pub"
|
||||
"github.com/superseriousbusiness/activity/streams"
|
||||
"github.com/superseriousbusiness/activity/streams/vocab"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
|
@ -111,7 +110,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote {
|
|||
|
||||
// Anyone can like.
|
||||
canLikeAlwaysProp := streams.NewGoToSocialAlwaysProperty()
|
||||
canLikeAlwaysProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
|
||||
canLikeAlwaysProp.AppendIRI(ap.PublicURI())
|
||||
canLike.SetGoToSocialAlways(canLikeAlwaysProp)
|
||||
|
||||
// Empty approvalRequired.
|
||||
|
@ -128,7 +127,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote {
|
|||
|
||||
// Anyone can reply.
|
||||
canReplyAlwaysProp := streams.NewGoToSocialAlwaysProperty()
|
||||
canReplyAlwaysProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
|
||||
canReplyAlwaysProp.AppendIRI(ap.PublicURI())
|
||||
canReply.SetGoToSocialAlways(canReplyAlwaysProp)
|
||||
|
||||
// Set empty approvalRequired.
|
||||
|
@ -151,7 +150,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote {
|
|||
|
||||
// Public requires approval to announce.
|
||||
canAnnounceApprovalRequiredProp := streams.NewGoToSocialApprovalRequiredProperty()
|
||||
canAnnounceApprovalRequiredProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
|
||||
canAnnounceApprovalRequiredProp.AppendIRI(ap.PublicURI())
|
||||
canAnnounce.SetGoToSocialApprovalRequired(canAnnounceApprovalRequiredProp)
|
||||
|
||||
// Set canAnnounce on the policy.
|
||||
|
@ -266,7 +265,7 @@ func addressable1() ap.Addressable {
|
|||
note := streams.NewActivityStreamsNote()
|
||||
|
||||
toProp := streams.NewActivityStreamsToProperty()
|
||||
toProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
|
||||
toProp.AppendIRI(ap.PublicURI())
|
||||
|
||||
note.SetActivityStreamsTo(toProp)
|
||||
|
||||
|
@ -288,7 +287,7 @@ func addressable2() ap.Addressable {
|
|||
note.SetActivityStreamsTo(toProp)
|
||||
|
||||
ccProp := streams.NewActivityStreamsCcProperty()
|
||||
ccProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
|
||||
ccProp.AppendIRI(ap.PublicURI())
|
||||
|
||||
note.SetActivityStreamsCc(ccProp)
|
||||
|
||||
|
|
|
@ -805,7 +805,7 @@ func extractHashtag(i Hashtaggable) (*gtsmodel.Tag, error) {
|
|||
// ExtractEmojis extracts a slice of minimal gtsmodel.Emojis
|
||||
// from a WithTag. If an entry in the WithTag is not an emoji,
|
||||
// it will be quietly ignored.
|
||||
func ExtractEmojis(i WithTag) ([]*gtsmodel.Emoji, error) {
|
||||
func ExtractEmojis(i WithTag, host string) ([]*gtsmodel.Emoji, error) {
|
||||
tagsProp := i.GetActivityStreamsTag()
|
||||
if tagsProp == nil {
|
||||
return nil, nil
|
||||
|
@ -827,7 +827,7 @@ func ExtractEmojis(i WithTag) ([]*gtsmodel.Emoji, error) {
|
|||
continue
|
||||
}
|
||||
|
||||
emoji, err := ExtractEmoji(tootEmoji)
|
||||
emoji, err := ExtractEmoji(tootEmoji, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -844,41 +844,57 @@ func ExtractEmojis(i WithTag) ([]*gtsmodel.Emoji, error) {
|
|||
return emojis, nil
|
||||
}
|
||||
|
||||
// ExtractEmoji extracts a minimal gtsmodel.Emoji
|
||||
// from the given Emojiable.
|
||||
func ExtractEmoji(i Emojiable) (*gtsmodel.Emoji, error) {
|
||||
// Use AP ID as emoji URI.
|
||||
idProp := i.GetJSONLDId()
|
||||
if idProp == nil || !idProp.IsIRI() {
|
||||
return nil, gtserror.New("no id for emoji")
|
||||
}
|
||||
uri := idProp.GetIRI()
|
||||
|
||||
// Extract emoji last updated time (optional).
|
||||
var updatedAt time.Time
|
||||
updatedProp := i.GetActivityStreamsUpdated()
|
||||
if updatedProp != nil && updatedProp.IsXMLSchemaDateTime() {
|
||||
updatedAt = updatedProp.Get()
|
||||
}
|
||||
|
||||
// Extract emoji name aka shortcode.
|
||||
name := ExtractName(i)
|
||||
// ExtractEmoji extracts a minimal gtsmodel.Emoji from
|
||||
// the given Emojiable. The host (eg., "example.org")
|
||||
// of the emoji should be passed in as well, so that a
|
||||
// dummy URI for the emoji can be constructed in case
|
||||
// there's no id property or id property is null.
|
||||
//
|
||||
// https://github.com/superseriousbusiness/gotosocial/issues/3384)
|
||||
func ExtractEmoji(
|
||||
e Emojiable,
|
||||
host string,
|
||||
) (*gtsmodel.Emoji, error) {
|
||||
// Extract emoji name,
|
||||
// eg., ":some_emoji".
|
||||
name := ExtractName(e)
|
||||
if name == "" {
|
||||
return nil, gtserror.New("name prop empty")
|
||||
}
|
||||
shortcode := strings.Trim(name, ":")
|
||||
name = strings.TrimSpace(name)
|
||||
|
||||
// Extract emoji image URL from Icon property.
|
||||
imageRemoteURL, err := ExtractIconURI(i)
|
||||
// Derive shortcode from
|
||||
// name, eg., "some_emoji".
|
||||
shortcode := strings.Trim(name, ":")
|
||||
shortcode = strings.TrimSpace(shortcode)
|
||||
|
||||
// Extract emoji image
|
||||
// URL from Icon property.
|
||||
imageRemoteURL, err := ExtractIconURI(e)
|
||||
if err != nil {
|
||||
return nil, gtserror.New("no url for emoji image")
|
||||
}
|
||||
imageRemoteURLStr := imageRemoteURL.String()
|
||||
|
||||
// Use AP ID as emoji URI, or fall
|
||||
// back to dummy URI if not present.
|
||||
uri := GetJSONLDId(e)
|
||||
if uri == nil {
|
||||
// No ID was set,
|
||||
// construct dummy.
|
||||
uri, err = url.Parse(
|
||||
// eg., https://example.org/dummy_emoji_path?shortcode=some_emoji
|
||||
"https://" + host + "/dummy_emoji_path?shortcode=" + url.QueryEscape(shortcode),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, gtserror.Newf("error constructing dummy path: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return >smodel.Emoji{
|
||||
UpdatedAt: updatedAt,
|
||||
UpdatedAt: GetUpdated(e),
|
||||
Shortcode: shortcode,
|
||||
Domain: uri.Host,
|
||||
Domain: host,
|
||||
ImageRemoteURL: imageRemoteURLStr,
|
||||
URI: uri.String(),
|
||||
Disabled: new(bool), // Assume false by default.
|
||||
|
|
255
internal/ap/extractemojis_test.go
Normal file
255
internal/ap/extractemojis_test.go
Normal file
|
@ -0,0 +1,255 @@
|
|||
// 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"
|
||||
"context"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
)
|
||||
|
||||
type ExtractEmojisTestSuite struct {
|
||||
APTestSuite
|
||||
}
|
||||
|
||||
func (suite *ExtractEmojisTestSuite) TestExtractEmojis() {
|
||||
const noteWithEmojis = `{
|
||||
"@context": [
|
||||
"https://gotosocial.org/ns",
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
{
|
||||
"Emoji": "toot:Emoji",
|
||||
"sensitive": "as:sensitive",
|
||||
"toot": "http://joinmastodon.org/ns#"
|
||||
}
|
||||
],
|
||||
"attributedTo": "https://example.org/users/tobi",
|
||||
"content": "<p>i hear that the GoToSocial devs are anti-capitalists and even <em>shocked gasp</em> communists :shocked_pikachu: totally unreasonable people</p>",
|
||||
"id": "https://example.org/users/tobi/statuses/01HV11D2BS7M94ZS499VBW7RX5",
|
||||
"tag": {
|
||||
"icon": {
|
||||
"mediaType": "image/png",
|
||||
"type": "Image",
|
||||
"url": "https://example.org/fileserver/01BPSX2MKCRVMD4YN4D71G9CP5/emoji/original/01AZY1Y5YQD6TREB5W50HGTCSZ.png"
|
||||
},
|
||||
"id": "https://example.org/emoji/01AZY1Y5YQD6TREB5W50HGTCSZ",
|
||||
"name": ":shocked_pikachu:",
|
||||
"type": "Emoji",
|
||||
"updated": "2022-11-17T11:36:05Z"
|
||||
},
|
||||
"to": "https://www.w3.org/ns/activitystreams#Public",
|
||||
"type": "Note"
|
||||
}`
|
||||
|
||||
statusable, err := ap.ResolveStatusable(
|
||||
context.Background(),
|
||||
io.NopCloser(bytes.NewBufferString(noteWithEmojis)),
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
emojis, err := ap.ExtractEmojis(statusable, "example.org")
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
if l := len(emojis); l != 1 {
|
||||
suite.FailNow("", "expected length 1 for emojis, got %d", l)
|
||||
}
|
||||
|
||||
emoji := emojis[0]
|
||||
suite.Equal("shocked_pikachu", emoji.Shortcode)
|
||||
suite.Equal("example.org", emoji.Domain)
|
||||
suite.Equal("https://example.org/fileserver/01BPSX2MKCRVMD4YN4D71G9CP5/emoji/original/01AZY1Y5YQD6TREB5W50HGTCSZ.png", emoji.ImageRemoteURL)
|
||||
suite.False(*emoji.Disabled)
|
||||
suite.Equal("https://example.org/emoji/01AZY1Y5YQD6TREB5W50HGTCSZ", emoji.URI)
|
||||
suite.False(*emoji.VisibleInPicker)
|
||||
}
|
||||
|
||||
func (suite *ExtractEmojisTestSuite) TestExtractEmojisNoID() {
|
||||
const noteWithEmojis = `{
|
||||
"@context": [
|
||||
"https://gotosocial.org/ns",
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
{
|
||||
"Emoji": "toot:Emoji",
|
||||
"sensitive": "as:sensitive",
|
||||
"toot": "http://joinmastodon.org/ns#"
|
||||
}
|
||||
],
|
||||
"attributedTo": "https://example.org/users/tobi",
|
||||
"content": "<p>i hear that the GoToSocial devs are anti-capitalists and even <em>shocked gasp</em> communists :shocked_pikachu: totally unreasonable people</p>",
|
||||
"id": "https://example.org/users/tobi/statuses/01HV11D2BS7M94ZS499VBW7RX5",
|
||||
"tag": {
|
||||
"icon": {
|
||||
"mediaType": "image/png",
|
||||
"type": "Image",
|
||||
"url": "https://example.org/fileserver/01BPSX2MKCRVMD4YN4D71G9CP5/emoji/original/01AZY1Y5YQD6TREB5W50HGTCSZ.png"
|
||||
},
|
||||
"name": ":shocked_pikachu:",
|
||||
"type": "Emoji",
|
||||
"updated": "2022-11-17T11:36:05Z"
|
||||
},
|
||||
"to": "https://www.w3.org/ns/activitystreams#Public",
|
||||
"type": "Note"
|
||||
}`
|
||||
|
||||
statusable, err := ap.ResolveStatusable(
|
||||
context.Background(),
|
||||
io.NopCloser(bytes.NewBufferString(noteWithEmojis)),
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
emojis, err := ap.ExtractEmojis(statusable, "example.org")
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
if l := len(emojis); l != 1 {
|
||||
suite.FailNow("", "expected length 1 for emojis, got %d", l)
|
||||
}
|
||||
|
||||
emoji := emojis[0]
|
||||
suite.Equal("shocked_pikachu", emoji.Shortcode)
|
||||
suite.Equal("example.org", emoji.Domain)
|
||||
suite.Equal("https://example.org/fileserver/01BPSX2MKCRVMD4YN4D71G9CP5/emoji/original/01AZY1Y5YQD6TREB5W50HGTCSZ.png", emoji.ImageRemoteURL)
|
||||
suite.False(*emoji.Disabled)
|
||||
suite.Equal("https://example.org/dummy_emoji_path?shortcode=shocked_pikachu", emoji.URI)
|
||||
suite.False(*emoji.VisibleInPicker)
|
||||
}
|
||||
|
||||
func (suite *ExtractEmojisTestSuite) TestExtractEmojisNullID() {
|
||||
const noteWithEmojis = `{
|
||||
"@context": [
|
||||
"https://gotosocial.org/ns",
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
{
|
||||
"Emoji": "toot:Emoji",
|
||||
"sensitive": "as:sensitive",
|
||||
"toot": "http://joinmastodon.org/ns#"
|
||||
}
|
||||
],
|
||||
"attributedTo": "https://example.org/users/tobi",
|
||||
"content": "<p>i hear that the GoToSocial devs are anti-capitalists and even <em>shocked gasp</em> communists :shocked_pikachu: totally unreasonable people</p>",
|
||||
"id": "https://example.org/users/tobi/statuses/01HV11D2BS7M94ZS499VBW7RX5",
|
||||
"tag": {
|
||||
"icon": {
|
||||
"mediaType": "image/png",
|
||||
"type": "Image",
|
||||
"url": "https://example.org/fileserver/01BPSX2MKCRVMD4YN4D71G9CP5/emoji/original/01AZY1Y5YQD6TREB5W50HGTCSZ.png"
|
||||
},
|
||||
"id": null,
|
||||
"name": ":shocked_pikachu:",
|
||||
"type": "Emoji",
|
||||
"updated": "2022-11-17T11:36:05Z"
|
||||
},
|
||||
"to": "https://www.w3.org/ns/activitystreams#Public",
|
||||
"type": "Note"
|
||||
}`
|
||||
|
||||
statusable, err := ap.ResolveStatusable(
|
||||
context.Background(),
|
||||
io.NopCloser(bytes.NewBufferString(noteWithEmojis)),
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
emojis, err := ap.ExtractEmojis(statusable, "example.org")
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
if l := len(emojis); l != 1 {
|
||||
suite.FailNow("", "expected length 1 for emojis, got %d", l)
|
||||
}
|
||||
|
||||
emoji := emojis[0]
|
||||
suite.Equal("shocked_pikachu", emoji.Shortcode)
|
||||
suite.Equal("example.org", emoji.Domain)
|
||||
suite.Equal("https://example.org/fileserver/01BPSX2MKCRVMD4YN4D71G9CP5/emoji/original/01AZY1Y5YQD6TREB5W50HGTCSZ.png", emoji.ImageRemoteURL)
|
||||
suite.False(*emoji.Disabled)
|
||||
suite.Equal("https://example.org/dummy_emoji_path?shortcode=shocked_pikachu", emoji.URI)
|
||||
suite.False(*emoji.VisibleInPicker)
|
||||
}
|
||||
|
||||
func (suite *ExtractEmojisTestSuite) TestExtractEmojisEmptyID() {
|
||||
const noteWithEmojis = `{
|
||||
"@context": [
|
||||
"https://gotosocial.org/ns",
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
{
|
||||
"Emoji": "toot:Emoji",
|
||||
"sensitive": "as:sensitive",
|
||||
"toot": "http://joinmastodon.org/ns#"
|
||||
}
|
||||
],
|
||||
"attributedTo": "https://example.org/users/tobi",
|
||||
"content": "<p>i hear that the GoToSocial devs are anti-capitalists and even <em>shocked gasp</em> communists :shocked_pikachu: totally unreasonable people</p>",
|
||||
"id": "https://example.org/users/tobi/statuses/01HV11D2BS7M94ZS499VBW7RX5",
|
||||
"tag": {
|
||||
"icon": {
|
||||
"mediaType": "image/png",
|
||||
"type": "Image",
|
||||
"url": "https://example.org/fileserver/01BPSX2MKCRVMD4YN4D71G9CP5/emoji/original/01AZY1Y5YQD6TREB5W50HGTCSZ.png"
|
||||
},
|
||||
"id": "",
|
||||
"name": ":shocked_pikachu:",
|
||||
"type": "Emoji",
|
||||
"updated": "2022-11-17T11:36:05Z"
|
||||
},
|
||||
"to": "https://www.w3.org/ns/activitystreams#Public",
|
||||
"type": "Note"
|
||||
}`
|
||||
|
||||
statusable, err := ap.ResolveStatusable(
|
||||
context.Background(),
|
||||
io.NopCloser(bytes.NewBufferString(noteWithEmojis)),
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
emojis, err := ap.ExtractEmojis(statusable, "example.org")
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
if l := len(emojis); l != 1 {
|
||||
suite.FailNow("", "expected length 1 for emojis, got %d", l)
|
||||
}
|
||||
|
||||
emoji := emojis[0]
|
||||
suite.Equal("shocked_pikachu", emoji.Shortcode)
|
||||
suite.Equal("example.org", emoji.Domain)
|
||||
suite.Equal("https://example.org/fileserver/01BPSX2MKCRVMD4YN4D71G9CP5/emoji/original/01AZY1Y5YQD6TREB5W50HGTCSZ.png", emoji.ImageRemoteURL)
|
||||
suite.False(*emoji.Disabled)
|
||||
suite.Equal("https://example.org/dummy_emoji_path?shortcode=shocked_pikachu", emoji.URI)
|
||||
suite.False(*emoji.VisibleInPicker)
|
||||
}
|
||||
|
||||
func TestExtractEmojisTestSuite(t *testing.T) {
|
||||
suite.Run(t, &ExtractEmojisTestSuite{})
|
||||
}
|
|
@ -188,6 +188,7 @@ type Accountable interface {
|
|||
WithTag
|
||||
WithPublished
|
||||
WithUpdated
|
||||
WithImage
|
||||
}
|
||||
|
||||
// Statusable represents the minimum activitypub interface for representing a 'status'.
|
||||
|
@ -439,6 +440,7 @@ type WithValue interface {
|
|||
// WithImage represents an activity with ActivityStreamsImageProperty
|
||||
type WithImage interface {
|
||||
GetActivityStreamsImage() vocab.ActivityStreamsImageProperty
|
||||
SetActivityStreamsImage(vocab.ActivityStreamsImageProperty)
|
||||
}
|
||||
|
||||
// WithSummary represents an activity with ActivityStreamsSummaryProperty
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/admin"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/activitypub/emoji"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/email"
|
||||
|
@ -73,6 +74,7 @@ func (suite *EmojiGetTestSuite) SetupTest() {
|
|||
|
||||
suite.db = testrig.NewTestDB(&suite.state)
|
||||
suite.state.DB = suite.db
|
||||
suite.state.AdminActions = admin.New(suite.state.DB, &suite.state.Workers)
|
||||
suite.storage = testrig.NewInMemoryStorage()
|
||||
suite.state.Storage = suite.storage
|
||||
suite.tc = typeutils.NewConverter(&suite.state)
|
||||
|
@ -86,7 +88,13 @@ func (suite *EmojiGetTestSuite) SetupTest() {
|
|||
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)
|
||||
suite.processor = testrig.NewTestProcessor(&suite.state, suite.federator, suite.emailSender, suite.mediaManager)
|
||||
suite.processor = testrig.NewTestProcessor(
|
||||
&suite.state,
|
||||
suite.federator,
|
||||
suite.emailSender,
|
||||
testrig.NewNoopWebPushSender(),
|
||||
suite.mediaManager,
|
||||
)
|
||||
suite.emojiModule = emoji.New(suite.processor)
|
||||
testrig.StandardDBSetup(suite.db, suite.testAccounts)
|
||||
testrig.StandardStorageSetup(suite.storage, "../../../../testrig/media")
|
||||
|
|
|
@ -177,38 +177,6 @@ func (suite *InboxPostTestSuite) newUndo(
|
|||
return undo
|
||||
}
|
||||
|
||||
func (suite *InboxPostTestSuite) newUpdatePerson(person vocab.ActivityStreamsPerson, cc string, updateIRI string) vocab.ActivityStreamsUpdate {
|
||||
// create an update
|
||||
update := streams.NewActivityStreamsUpdate()
|
||||
|
||||
// set the appropriate actor on it
|
||||
updateActor := streams.NewActivityStreamsActorProperty()
|
||||
updateActor.AppendIRI(person.GetJSONLDId().Get())
|
||||
update.SetActivityStreamsActor(updateActor)
|
||||
|
||||
// Set the person as the 'object' property.
|
||||
updateObject := streams.NewActivityStreamsObjectProperty()
|
||||
updateObject.AppendActivityStreamsPerson(person)
|
||||
update.SetActivityStreamsObject(updateObject)
|
||||
|
||||
// Set the To of the update as public
|
||||
updateTo := streams.NewActivityStreamsToProperty()
|
||||
updateTo.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
|
||||
update.SetActivityStreamsTo(updateTo)
|
||||
|
||||
// set the cc of the update to the receivingAccount
|
||||
updateCC := streams.NewActivityStreamsCcProperty()
|
||||
updateCC.AppendIRI(testrig.URLMustParse(cc))
|
||||
update.SetActivityStreamsCc(updateCC)
|
||||
|
||||
// set some random-ass ID for the activity
|
||||
updateID := streams.NewJSONLDIdProperty()
|
||||
updateID.SetIRI(testrig.URLMustParse(updateIRI))
|
||||
update.SetJSONLDId(updateID)
|
||||
|
||||
return update
|
||||
}
|
||||
|
||||
func (suite *InboxPostTestSuite) newDelete(actorIRI string, objectIRI string, deleteIRI string) vocab.ActivityStreamsDelete {
|
||||
// create a delete
|
||||
delete := streams.NewActivityStreamsDelete()
|
||||
|
@ -225,7 +193,7 @@ func (suite *InboxPostTestSuite) newDelete(actorIRI string, objectIRI string, de
|
|||
|
||||
// Set the To of the delete as public
|
||||
deleteTo := streams.NewActivityStreamsToProperty()
|
||||
deleteTo.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
|
||||
deleteTo.AppendIRI(ap.PublicURI())
|
||||
delete.SetActivityStreamsTo(deleteTo)
|
||||
|
||||
// set some random-ass ID for the activity
|
||||
|
@ -329,7 +297,6 @@ func (suite *InboxPostTestSuite) TestPostUpdate() {
|
|||
var (
|
||||
requestingAccount = new(gtsmodel.Account)
|
||||
targetAccount = suite.testAccounts["local_account_1"]
|
||||
activityID = "http://fossbros-anonymous.io/72cc96a3-f742-4daf-b9f5-3407667260c5"
|
||||
updatedDisplayName = "updated display name!"
|
||||
)
|
||||
|
||||
|
@ -348,11 +315,19 @@ func (suite *InboxPostTestSuite) TestPostUpdate() {
|
|||
requestingAccount.Emojis = []*gtsmodel.Emoji{testEmoji}
|
||||
|
||||
// Create an update from the account.
|
||||
asAccount, err := suite.tc.AccountToAS(context.Background(), requestingAccount)
|
||||
accountable, err := suite.tc.AccountToAS(context.Background(), requestingAccount)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
update := suite.newUpdatePerson(asAccount, targetAccount.URI, activityID)
|
||||
update, err := suite.tc.WrapAccountableInUpdate(accountable)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
// Set the ID to something from fossbros anonymous.
|
||||
idProp := streams.NewJSONLDIdProperty()
|
||||
idProp.SetIRI(testrig.URLMustParse("https://fossbros-anonymous.io/updates/waaaaaaaaaaaaaaaaa"))
|
||||
update.SetJSONLDId(idProp)
|
||||
|
||||
// Update.
|
||||
suite.inboxPost(
|
||||
|
@ -540,17 +515,20 @@ func (suite *InboxPostTestSuite) TestPostFromBlockedAccount() {
|
|||
var (
|
||||
requestingAccount = suite.testAccounts["remote_account_1"]
|
||||
targetAccount = suite.testAccounts["local_account_2"]
|
||||
activityID = requestingAccount.URI + "/some-new-activity/01FG9C441MCTW3R2W117V2PQK3"
|
||||
)
|
||||
|
||||
person, err := suite.tc.AccountToAS(context.Background(), requestingAccount)
|
||||
// Create an update from the account.
|
||||
accountable, err := suite.tc.AccountToAS(context.Background(), requestingAccount)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
update, err := suite.tc.WrapAccountableInUpdate(accountable)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
// Post an update from foss satan to turtle, who blocks him.
|
||||
update := suite.newUpdatePerson(person, targetAccount.URI, activityID)
|
||||
|
||||
// Post an update from foss satan
|
||||
// to turtle, who blocks him.
|
||||
suite.inboxPost(
|
||||
update,
|
||||
requestingAccount,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/admin"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/activitypub/users"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/email"
|
||||
|
@ -84,6 +85,7 @@ func (suite *UserStandardTestSuite) SetupTest() {
|
|||
|
||||
suite.db = testrig.NewTestDB(&suite.state)
|
||||
suite.state.DB = suite.db
|
||||
suite.state.AdminActions = admin.New(suite.state.DB, &suite.state.Workers)
|
||||
suite.tc = typeutils.NewConverter(&suite.state)
|
||||
|
||||
testrig.StartTimelines(
|
||||
|
@ -98,7 +100,13 @@ func (suite *UserStandardTestSuite) SetupTest() {
|
|||
suite.federator = testrig.NewTestFederator(&suite.state, testrig.NewTestTransportController(&suite.state, testrig.NewMockHTTPClient(nil, "../../../../testrig/media")), suite.mediaManager)
|
||||
suite.emailSender = testrig.NewEmailSender("../../../../web/template/", nil)
|
||||
|
||||
suite.processor = testrig.NewTestProcessor(&suite.state, suite.federator, suite.emailSender, suite.mediaManager)
|
||||
suite.processor = testrig.NewTestProcessor(
|
||||
&suite.state,
|
||||
suite.federator,
|
||||
suite.emailSender,
|
||||
testrig.NewNoopWebPushSender(),
|
||||
suite.mediaManager,
|
||||
)
|
||||
testrig.StartWorkers(&suite.state, suite.processor.Workers())
|
||||
|
||||
suite.userModule = users.New(suite.processor)
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
"github.com/gin-contrib/sessions/memstore"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/admin"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/auth"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
|
@ -84,12 +85,19 @@ func (suite *AuthStandardTestSuite) SetupTest() {
|
|||
|
||||
suite.db = testrig.NewTestDB(&suite.state)
|
||||
suite.state.DB = suite.db
|
||||
suite.state.AdminActions = admin.New(suite.state.DB, &suite.state.Workers)
|
||||
suite.storage = testrig.NewInMemoryStorage()
|
||||
suite.state.Storage = suite.storage
|
||||
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)
|
||||
suite.processor = testrig.NewTestProcessor(&suite.state, suite.federator, suite.emailSender, suite.mediaManager)
|
||||
suite.processor = testrig.NewTestProcessor(
|
||||
&suite.state,
|
||||
suite.federator,
|
||||
suite.emailSender,
|
||||
testrig.NewNoopWebPushSender(),
|
||||
suite.mediaManager,
|
||||
)
|
||||
suite.authModule = auth.New(suite.db, suite.processor, suite.idp)
|
||||
|
||||
testrig.StandardDBSetup(suite.db, suite.testAccounts)
|
||||
|
|
|
@ -145,12 +145,18 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// Since we require lowercase usernames at this point, lowercase the one
|
||||
// from the claims and use this to autofill the form with a suggestion.
|
||||
//
|
||||
// Pending https://github.com/superseriousbusiness/gotosocial/issues/1813
|
||||
suggestedUsername := strings.ToLower(claims.PreferredUsername)
|
||||
|
||||
page := apiutil.WebPage{
|
||||
Template: "finalize.tmpl",
|
||||
Instance: instance,
|
||||
Extra: map[string]any{
|
||||
"name": claims.Name,
|
||||
"preferredUsername": claims.PreferredUsername,
|
||||
"suggestedUsername": suggestedUsername,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
"github.com/gin-gonic/gin"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/accounts"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/admin"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/announcements"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/apps"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/blocks"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/bookmarks"
|
||||
|
@ -46,6 +47,7 @@
|
|||
"github.com/superseriousbusiness/gotosocial/internal/api/client/notifications"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/polls"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/preferences"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/push"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/reports"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/search"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/statuses"
|
||||
|
@ -66,6 +68,7 @@ type Client struct {
|
|||
|
||||
accounts *accounts.Module // api/v1/accounts, api/v1/profile
|
||||
admin *admin.Module // api/v1/admin
|
||||
announcements *announcements.Module // api/v1/announcements
|
||||
apps *apps.Module // api/v1/apps
|
||||
blocks *blocks.Module // api/v1/blocks
|
||||
bookmarks *bookmarks.Module // api/v1/bookmarks
|
||||
|
@ -89,6 +92,7 @@ type Client struct {
|
|||
notifications *notifications.Module // api/v1/notifications
|
||||
polls *polls.Module // api/v1/polls
|
||||
preferences *preferences.Module // api/v1/preferences
|
||||
push *push.Module // api/v1/push
|
||||
reports *reports.Module // api/v1/reports
|
||||
search *search.Module // api/v1/search, api/v2/search
|
||||
statuses *statuses.Module // api/v1/statuses
|
||||
|
@ -117,6 +121,7 @@ func (c *Client) Route(r *router.Router, m ...gin.HandlerFunc) {
|
|||
h := apiGroup.Handle
|
||||
c.accounts.Route(h)
|
||||
c.admin.Route(h)
|
||||
c.announcements.Route(h)
|
||||
c.apps.Route(h)
|
||||
c.blocks.Route(h)
|
||||
c.bookmarks.Route(h)
|
||||
|
@ -140,6 +145,7 @@ func (c *Client) Route(r *router.Router, m ...gin.HandlerFunc) {
|
|||
c.notifications.Route(h)
|
||||
c.polls.Route(h)
|
||||
c.preferences.Route(h)
|
||||
c.push.Route(h)
|
||||
c.reports.Route(h)
|
||||
c.search.Route(h)
|
||||
c.statuses.Route(h)
|
||||
|
@ -156,6 +162,7 @@ func NewClient(state *state.State, p *processing.Processor) *Client {
|
|||
|
||||
accounts: accounts.New(p),
|
||||
admin: admin.New(state, p),
|
||||
announcements: announcements.New(p),
|
||||
apps: apps.New(p),
|
||||
blocks: blocks.New(p),
|
||||
bookmarks: bookmarks.New(p),
|
||||
|
@ -179,6 +186,7 @@ func NewClient(state *state.State, p *processing.Processor) *Client {
|
|||
notifications: notifications.New(p),
|
||||
polls: polls.New(p),
|
||||
preferences: preferences.New(p),
|
||||
push: push.New(p),
|
||||
reports: reports.New(p),
|
||||
search: search.New(p),
|
||||
statuses: statuses.New(p),
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/admin"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/accounts"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
|
@ -85,6 +86,7 @@ func (suite *AccountStandardTestSuite) SetupTest() {
|
|||
|
||||
suite.db = testrig.NewTestDB(&suite.state)
|
||||
suite.state.DB = suite.db
|
||||
suite.state.AdminActions = admin.New(suite.state.DB, &suite.state.Workers)
|
||||
suite.storage = testrig.NewInMemoryStorage()
|
||||
suite.state.Storage = suite.storage
|
||||
|
||||
|
@ -98,7 +100,13 @@ func (suite *AccountStandardTestSuite) SetupTest() {
|
|||
suite.federator = testrig.NewTestFederator(&suite.state, testrig.NewTestTransportController(&suite.state, testrig.NewMockHTTPClient(nil, "../../../../testrig/media")), suite.mediaManager)
|
||||
suite.sentEmails = make(map[string]string)
|
||||
suite.emailSender = testrig.NewEmailSender("../../../../web/template/", suite.sentEmails)
|
||||
suite.processor = testrig.NewTestProcessor(&suite.state, suite.federator, suite.emailSender, suite.mediaManager)
|
||||
suite.processor = testrig.NewTestProcessor(
|
||||
&suite.state,
|
||||
suite.federator,
|
||||
suite.emailSender,
|
||||
testrig.NewNoopWebPushSender(),
|
||||
suite.mediaManager,
|
||||
)
|
||||
suite.accountsModule = accounts.New(suite.processor)
|
||||
testrig.StandardDBSetup(suite.db, nil)
|
||||
testrig.StandardStorageSetup(suite.storage, "../../../../testrig/media")
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
BlockPath = BasePathWithID + "/block"
|
||||
DeletePath = BasePath + "/delete"
|
||||
FeaturedTagsPath = BasePathWithID + "/featured_tags"
|
||||
FollowersPath = BasePathWithID + "/followers"
|
||||
FollowingPath = BasePathWithID + "/following"
|
||||
FollowPath = BasePathWithID + "/follow"
|
||||
|
@ -98,6 +99,9 @@ func (m *Module) Route(attachHandler func(method string, path string, f ...gin.H
|
|||
// get account's statuses
|
||||
attachHandler(http.MethodGet, StatusesPath, m.AccountStatusesGETHandler)
|
||||
|
||||
// get account's featured tags
|
||||
attachHandler(http.MethodGet, FeaturedTagsPath, m.AccountFeaturedTagsGETHandler)
|
||||
|
||||
// get following or followers
|
||||
attachHandler(http.MethodGet, FollowersPath, m.AccountFollowersGETHandler)
|
||||
attachHandler(http.MethodGet, FollowingPath, m.AccountFollowingGETHandler)
|
||||
|
|
83
internal/api/client/accounts/featuredtags.go
Normal file
83
internal/api/client/accounts/featuredtags.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
// 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 accounts
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||
)
|
||||
|
||||
// AccountFeaturedTagsGETHandler swagger:operation GET /api/v1/accounts/{id}/featured_tags accountsFeaturedTags
|
||||
//
|
||||
// Get an array of target account's featured tags.
|
||||
//
|
||||
// THIS ENDPOINT IS CURRENTLY NOT FULLY IMPLEMENTED: it will always return an empty array.
|
||||
//
|
||||
// ---
|
||||
// tags:
|
||||
// - accounts
|
||||
//
|
||||
// produces:
|
||||
// - application/json
|
||||
//
|
||||
// parameters:
|
||||
// -
|
||||
// name: id
|
||||
// type: string
|
||||
// description: The id of the account.
|
||||
// in: path
|
||||
// required: true
|
||||
//
|
||||
// security:
|
||||
// - OAuth2 Bearer:
|
||||
// - read:accounts
|
||||
//
|
||||
// responses:
|
||||
// '200':
|
||||
// schema:
|
||||
// type: array
|
||||
// items:
|
||||
// type: object
|
||||
// '400':
|
||||
// description: bad request
|
||||
// '401':
|
||||
// description: unauthorized
|
||||
// '404':
|
||||
// description: not found
|
||||
// '406':
|
||||
// description: not acceptable
|
||||
// '500':
|
||||
// description: internal server error
|
||||
func (m *Module) AccountFeaturedTagsGETHandler(c *gin.Context) {
|
||||
_, err := oauth.Authed(c, true, true, true, true)
|
||||
if err != nil {
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
apiutil.Data(c, http.StatusOK, apiutil.AppJSON, apiutil.EmptyJSONArray)
|
||||
}
|
|
@ -114,7 +114,8 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
|
|||
"verified_at": null
|
||||
}
|
||||
],
|
||||
"hide_collections": true
|
||||
"hide_collections": true,
|
||||
"group": false
|
||||
},
|
||||
"created_by_application_id": "01F8MGY43H3N2C8EWPR2FPYEXG"
|
||||
},
|
||||
|
@ -169,7 +170,8 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
|
|||
"name": "admin",
|
||||
"color": ""
|
||||
}
|
||||
]
|
||||
],
|
||||
"group": false
|
||||
},
|
||||
"created_by_application_id": "01F8MGXQRHYF5QPMTMXP78QC2F"
|
||||
},
|
||||
|
@ -216,7 +218,8 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
|
|||
"statuses_count": 0,
|
||||
"last_status_at": null,
|
||||
"emojis": [],
|
||||
"fields": []
|
||||
"fields": [],
|
||||
"group": false
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -266,7 +269,8 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
|
|||
"last_status_at": "2024-11-01",
|
||||
"emojis": [],
|
||||
"fields": [],
|
||||
"enable_rss": true
|
||||
"enable_rss": true,
|
||||
"group": false
|
||||
},
|
||||
"created_by_application_id": "01F8MGY43H3N2C8EWPR2FPYEXG"
|
||||
},
|
||||
|
@ -313,7 +317,8 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
|
|||
"statuses_count": 0,
|
||||
"last_status_at": null,
|
||||
"emojis": [],
|
||||
"fields": []
|
||||
"fields": [],
|
||||
"group": false
|
||||
},
|
||||
"created_by_application_id": "01F8MGY43H3N2C8EWPR2FPYEXG"
|
||||
},
|
||||
|
@ -360,7 +365,8 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
|
|||
"statuses_count": 1,
|
||||
"last_status_at": "2023-11-02",
|
||||
"emojis": [],
|
||||
"fields": []
|
||||
"fields": [],
|
||||
"group": false
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -406,7 +412,8 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
|
|||
"statuses_count": 4,
|
||||
"last_status_at": "2024-11-01",
|
||||
"emojis": [],
|
||||
"fields": []
|
||||
"fields": [],
|
||||
"group": false
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -453,7 +460,8 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
|
|||
"statuses_count": 0,
|
||||
"last_status_at": null,
|
||||
"emojis": [],
|
||||
"fields": []
|
||||
"fields": [],
|
||||
"group": false
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -499,7 +507,8 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
|
|||
"statuses_count": 0,
|
||||
"last_status_at": null,
|
||||
"emojis": [],
|
||||
"fields": []
|
||||
"fields": [],
|
||||
"group": false
|
||||
}
|
||||
}
|
||||
]`, dst.String())
|
||||
|
@ -584,7 +593,8 @@ func (suite *AccountsGetTestSuite) TestAccountsMinID() {
|
|||
"statuses_count": 0,
|
||||
"last_status_at": null,
|
||||
"emojis": [],
|
||||
"fields": []
|
||||
"fields": [],
|
||||
"group": false
|
||||
}
|
||||
}
|
||||
]`, dst.String())
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue