Merge pull request #231 from ssb-ngi-pointer/docs-refactor
reorganize the docs into deployment & development
This commit is contained in:
commit
77d204d888
|
@ -36,8 +36,7 @@ nfpms:
|
||||||
linux: Linux
|
linux: Linux
|
||||||
amd64: x86_64
|
amd64: x86_64
|
||||||
vendor: Secure-Scuttlebutt Community
|
vendor: Secure-Scuttlebutt Community
|
||||||
# TODO: make sure this email works
|
maintainer: Go-SSB-Room NGI-Pointer Team <go-ssb-room@ssb-ngi-pointer.email>
|
||||||
maintainer: SSB NGI-Pointer Team <go-ssb-room@ssb-ngi-pointer.eu>
|
|
||||||
homepage: https://scuttlebutt.nz
|
homepage: https://scuttlebutt.nz
|
||||||
description: SSB Room v2 server, written in Go
|
description: SSB Room v2 server, written in Go
|
||||||
license: MIT
|
license: MIT
|
||||||
|
@ -49,21 +48,21 @@ nfpms:
|
||||||
empty_folders:
|
empty_folders:
|
||||||
- /var/log/go-ssb-room
|
- /var/log/go-ssb-room
|
||||||
contents:
|
contents:
|
||||||
- src: docs/example-systemd.service
|
- src: docs/files/example-systemd.service
|
||||||
dst: /etc/systemd/system/go-ssb-room.service
|
dst: /etc/systemd/system/go-ssb-room.service
|
||||||
type: "config|noreplace"
|
type: "config|noreplace"
|
||||||
|
|
||||||
- src: docs/example-nginx.conf
|
- src: docs/files/example-nginx.conf
|
||||||
dst: /usr/share/go-ssb-room/nginx-example.conf
|
dst: /usr/share/go-ssb-room/nginx-example.conf
|
||||||
|
|
||||||
# TODO: maybe (automatically) turn docs/README.md into a .txt with the links at the bottom?
|
# TODO: maybe (automatically) turn docs/README.md into a .txt with the links at the bottom?
|
||||||
- src: docs/README.md
|
- src: README.md
|
||||||
dst: /usr/share/go-ssb-room/README.md
|
dst: /usr/share/go-ssb-room/README.md
|
||||||
|
|
||||||
# TODO: add more docs we want?
|
# TODO: add more docs we want?
|
||||||
scripts:
|
scripts:
|
||||||
postinstall: docs/debian/postinstall.sh
|
postinstall: docs/files/debian-postinstall.sh
|
||||||
preremove: docs/debian/preremove.sh
|
preremove: docs/files/debian-preremove.sh
|
||||||
|
|
||||||
archives:
|
archives:
|
||||||
- replacements:
|
- replacements:
|
||||||
|
@ -72,7 +71,7 @@ archives:
|
||||||
|
|
||||||
checksum:
|
checksum:
|
||||||
name_template: 'checksums.txt'
|
name_template: 'checksums.txt'
|
||||||
|
|
||||||
snapshot:
|
snapshot:
|
||||||
name_template: "{{ .Tag }}-next"
|
name_template: "{{ .Tag }}-next"
|
||||||
|
|
||||||
|
|
35
README.md
35
README.md
|
@ -1,7 +1,6 @@
|
||||||
# Go-SSB Room
|
# Go-SSB Room
|
||||||
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fssb-ngi-pointer%2Fgo-ssb-room.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fssb-ngi-pointer%2Fgo-ssb-room?ref=badge_shield)
|
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fssb-ngi-pointer%2Fgo-ssb-room.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fssb-ngi-pointer%2Fgo-ssb-room?ref=badge_shield)
|
||||||
|
|
||||||
|
|
||||||
This repository contains code for a [Secure Scuttlebutt](https://ssb.nz) [Room (v1+v2) server](https://github.com/ssb-ngi-pointer/rooms2), written in Go.
|
This repository contains code for a [Secure Scuttlebutt](https://ssb.nz) [Room (v1+v2) server](https://github.com/ssb-ngi-pointer/rooms2), written in Go.
|
||||||
|
|
||||||
It includes:
|
It includes:
|
||||||
|
@ -9,33 +8,26 @@ It includes:
|
||||||
* muxrpc handlers for tunneling connections
|
* muxrpc handlers for tunneling connections
|
||||||
* a fully embedded HTTP server & HTML frontend, for administering the room
|
* a fully embedded HTTP server & HTML frontend, for administering the room
|
||||||
|
|
||||||
![](./docs/screenshot.png)
|
![](./docs/images/screenshot.png)
|
||||||
|
|
||||||
## Features
|
## :star: Features
|
||||||
|
|
||||||
* [x] Rooms v1 (`tunnel.connect`, `tunnel.endpoints`, etc.)
|
* Rooms v1 (`tunnel.connect`, `tunnel.endpoints`, etc.)
|
||||||
* [x] User management (allow- & denylisting + moderator & administrator roles), all administered via the web dashboard
|
* User management (allow- & denylisting + moderator & administrator roles), all administered via the web dashboard
|
||||||
* [x] Multiple [privacy modes](https://ssb-ngi-pointer.github.io/rooms2/#privacy-modes)
|
* Multiple [privacy modes](https://ssb-ngi-pointer.github.io/rooms2/#privacy-modes)
|
||||||
* [x] [Sign-in with SSB](https://ssb-ngi-pointer.github.io/ssb-http-auth-spec/)
|
* [Sign-in with SSB](https://ssb-ngi-pointer.github.io/ssb-http-auth-spec/)
|
||||||
* [x] Alias management
|
* [HTTP Invites](https://github.com/ssb-ngi-pointer/ssb-http-invite-spec)
|
||||||
|
* Alias management
|
||||||
|
|
||||||
## Getting started
|
## :rocket: Deployment
|
||||||
|
|
||||||
For an architecture and instructions on setting up a webserver to use with `go-ssb-room`, [read the documentation](./docs).
|
If you want to deploy a room server yourself, follow our [deployment.md](./docs/deployment.md) docs.
|
||||||
|
|
||||||
## Installation
|
## :wrench: Development
|
||||||
|
|
||||||
See the [releases page](https://github.com/ssb-ngi-pointer/go-ssb-room/releases) for packaged linux releases.
|
For an in-depth codebase walkthrough, see the [development.md](./docs/development.md) file in the `docs` folder of this repository.
|
||||||
|
|
||||||
We currently only distributed pre-packaged releases for debian-compatible distributions. See [Issue #79](https://github.com/ssb-ngi-pointer/go-ssb-room/issues/79) for the details. If this doesn't work for you, we ask you to read the Development notes and build from source.
|
## :people_holding_hands: Authors
|
||||||
|
|
||||||
After running `sudo dpkg -i go-ssb-room_v1.2.3_Linux_x86_64.deb` pay special attention to the [postinstall notes](./docs/debian/postinstall.sh) for how to configure the systemd file and webserver.
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
For an in-depth walkthrough, see the [development.md](./docs/development.md) in the `docs` folder of this repository.
|
|
||||||
|
|
||||||
## Authors
|
|
||||||
|
|
||||||
* [cryptix](https://github.com/cryptix) (`@p13zSAiOpguI9nsawkGijsnMfWmFd5rlUNpzekEE+vI=.ed25519`)
|
* [cryptix](https://github.com/cryptix) (`@p13zSAiOpguI9nsawkGijsnMfWmFd5rlUNpzekEE+vI=.ed25519`)
|
||||||
* [staltz](https://github.com/staltz)
|
* [staltz](https://github.com/staltz)
|
||||||
|
@ -45,5 +37,4 @@ For an in-depth walkthrough, see the [development.md](./docs/development.md) in
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|
||||||
|
|
||||||
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fssb-ngi-pointer%2Fgo-ssb-room.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fssb-ngi-pointer%2Fgo-ssb-room?ref=badge_large)
|
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fssb-ngi-pointer%2Fgo-ssb-room.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fssb-ngi-pointer%2Fgo-ssb-room?ref=badge_large)
|
|
@ -1,90 +1,6 @@
|
||||||
# Getting Started
|
## Table of contents
|
||||||
There are two paths to starting your own room: creating a build from source, or downloading one
|
|
||||||
of the premade [releases](https://github.com/ssb-ngi-pointer/go-ssb-room/releases).
|
|
||||||
|
|
||||||
## Creating a build
|
- [**Deployment**](./deployment.md)
|
||||||
* [Download Go](https://golang.org/doc/install) & [set up your Go environment](https://golang.org/doc/install#install). You will need at least Go v1.16.
|
- [**Development**](./development.md)
|
||||||
* Download the repository `git clone git@github.com:ssb-ngi-pointer/go-ssb-room.git && cd go-ssb-room`
|
- [**Architecture**](./architecture.md)
|
||||||
* [Read the development instructions](../README.md)
|
- [**Testing**](./testing.md)
|
||||||
* You should now have a working go-ssb-room binary! Read the HTTP Hosting and admin user sections below, for
|
|
||||||
more instructions on the last mile.
|
|
||||||
|
|
||||||
# Architecture
|
|
||||||
|
|
||||||
## Invite flow
|
|
||||||
|
|
||||||
This implementation of Rooms 2.0 is compliant with the [Rooms 2.0
|
|
||||||
specification](https://github.com/ssb-ngi-pointer/rooms2), but we add a few additional features
|
|
||||||
and pages in order to improve user experience when their SSB app does not support [SSB
|
|
||||||
URIs](https://github.com/ssb-ngi-pointer/ssb-uri-spec).
|
|
||||||
|
|
||||||
A summary can be seen in the following chart:
|
|
||||||
|
|
||||||
![Chart](./invites-chart.png)
|
|
||||||
|
|
||||||
When the browser and operating system detects no support for opening SSB URIs, we redirect to a
|
|
||||||
fallback page which presents the user with two broad options: (1) install an SSB app that
|
|
||||||
supports SSB URIs, (2) link to another page where the user can manually input the user's SSB ID
|
|
||||||
in a form.
|
|
||||||
|
|
||||||
## Sign-in flow
|
|
||||||
|
|
||||||
This implementation is compliant with [SSB HTTP
|
|
||||||
Authentication](https://github.com/ssb-ngi-pointer/ssb-http-auth-spec), but we add a few
|
|
||||||
additional features and pages in order to improve user experience. For instance, besides
|
|
||||||
conventional SSB HTTP Auth, we also render a QR code to sign-in with a remote SSB app (an SSB
|
|
||||||
identity not on the device that has the browser open). We also support sign-in with
|
|
||||||
username/password, what we call "fallback authentication".
|
|
||||||
|
|
||||||
A summary can be seen in the following chart:
|
|
||||||
|
|
||||||
![Chart](./login-chart.png)
|
|
||||||
|
|
||||||
# HTTP Hosting
|
|
||||||
|
|
||||||
We currently assume a standard HTTPS server in front of go-ssb-room to facilitate TLS
|
|
||||||
termination and certificate management. This should be possible with most modern HTTP servers
|
|
||||||
since it's a pretty standard practice, known as [reverse
|
|
||||||
proxying](https://en.wikipedia.org/wiki/Reverse_proxy).
|
|
||||||
|
|
||||||
Two bits of rationale:
|
|
||||||
|
|
||||||
1) People usually want to have more than one site on their server. Put differently, we could
|
|
||||||
have [LetsEncrypt](https://letsencrypt.org/) inside the go-ssb-room server but it would have to
|
|
||||||
listen on port :443—blocking the use of other domains on the same IP. 2) Listening on :443 can
|
|
||||||
be pretty annoying (you might need root privileges or similar capabilities).
|
|
||||||
|
|
||||||
go-ssb-room needs three headers to function properly, which need to be forwarded by the
|
|
||||||
webserver.
|
|
||||||
|
|
||||||
* `X-Forwarded-Host` as which domain name the room is running (enforce strict TLS checking)
|
|
||||||
* `X-Forwarded-Proto` to ensure that TLS is used (and redirect if necessary)
|
|
||||||
* `X-Forwarded-For` the remote TCP/IP address of the client accessing the room (used for rate
|
|
||||||
limiting)
|
|
||||||
|
|
||||||
[example-nginx.conf](./example-nginx.conf) contains an [nginx](https://nginx.org) config that
|
|
||||||
we use for [hermies.club](https://hermies.club). To get a wildcard TLS certificate you can
|
|
||||||
follow the steps in [this
|
|
||||||
article](https://medium.com/@alitou/getting-a-wildcard-ssl-certificate-using-certbot-and-deploy-on-nginx-15b8ffa34157),
|
|
||||||
which uses the [certbot](https://certbot.eff.org/) utility.
|
|
||||||
|
|
||||||
# First Admin user
|
|
||||||
|
|
||||||
To manage your now working server, you need an initial admin user. For this you can use the "insert-user" utility included with go-ssb-room.
|
|
||||||
In a new terminal window navigate to the insert-user utility folder and compile the GO-based utility into an executable your computer can use
|
|
||||||
|
|
||||||
```
|
|
||||||
cd cmd/insert-user
|
|
||||||
go build
|
|
||||||
```
|
|
||||||
|
|
||||||
A new executable file should be created called "insert-user"
|
|
||||||
Execute the `./insert-user -h` command to get a full list of custom options (optional location of the repo & SQLite database and user role). follow the instructions given in the output you receive.
|
|
||||||
|
|
||||||
example (with custom repo location, only needed if you setup your with a custom repo):
|
|
||||||
|
|
||||||
```
|
|
||||||
./insert-user -repo "/ssb-go-room-secrets" "@Bp5Z5TQKv6E/Y+QZn/3LiDWMPi63EP8MHsXZ4tiIb2w=.ed25519"
|
|
||||||
```
|
|
||||||
|
|
||||||
You can now login in the web-front-end using these credentials
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Architecture
|
||||||
|
|
||||||
|
## Invite flow
|
||||||
|
|
||||||
|
This implementation of Rooms 2.0 is compliant with the [Rooms 2.0
|
||||||
|
specification](https://github.com/ssb-ngi-pointer/rooms2), but we add a few additional features
|
||||||
|
and pages in order to improve user experience when their SSB app does not support [SSB
|
||||||
|
URIs](https://github.com/ssb-ngi-pointer/ssb-uri-spec).
|
||||||
|
|
||||||
|
A summary can be seen in the following chart:
|
||||||
|
|
||||||
|
![Chart](./images/invites-chart.png)
|
||||||
|
|
||||||
|
When the browser and operating system detects no support for opening SSB URIs, we redirect to a
|
||||||
|
fallback page which presents the user with two broad options: (1) install an SSB app that
|
||||||
|
supports SSB URIs, (2) link to another page where the user can manually input the user's SSB ID
|
||||||
|
in a form.
|
||||||
|
|
||||||
|
## Sign-in flow
|
||||||
|
|
||||||
|
This implementation is compliant with [SSB HTTP
|
||||||
|
Authentication](https://github.com/ssb-ngi-pointer/ssb-http-auth-spec), but we add a few
|
||||||
|
additional features and pages in order to improve user experience. For instance, besides
|
||||||
|
conventional SSB HTTP Auth, we also render a QR code to sign-in with a remote SSB app (an SSB
|
||||||
|
identity not on the device that has the browser open). We also support sign-in with
|
||||||
|
username/password, what we call "fallback authentication".
|
||||||
|
|
||||||
|
A summary can be seen in the following chart:
|
||||||
|
|
||||||
|
![Chart](./images/login-chart.png)
|
|
@ -0,0 +1,71 @@
|
||||||
|
# Getting Started
|
||||||
|
There are two paths to starting your own room: creating a build from source, or downloading one
|
||||||
|
of the premade releases.
|
||||||
|
|
||||||
|
## Premade builds
|
||||||
|
|
||||||
|
See the [releases page](https://github.com/ssb-ngi-pointer/go-ssb-room/releases) for packaged linux releases.
|
||||||
|
|
||||||
|
We currently only distributed pre-packaged releases for Debian-compatible distributions.
|
||||||
|
See [Issue #79](https://github.com/ssb-ngi-pointer/go-ssb-room/issues/79) for the details.
|
||||||
|
If this doesn't work for you, read the "Creating a build" section below.
|
||||||
|
|
||||||
|
After running `sudo dpkg -i go-ssb-room_v1.2.3_Linux_x86_64.deb` pay special attention to the
|
||||||
|
[postinstall notes](./files/debian-postinstall.sh) for how to configure the systemd file and webserver.
|
||||||
|
|
||||||
|
## Creating a build
|
||||||
|
|
||||||
|
* [Download Go](https://golang.org/doc/install) & [set up your Go environment](https://golang.org/doc/install#install). You will need at least Go v1.16.
|
||||||
|
* Download the repository `git clone git@github.com:ssb-ngi-pointer/go-ssb-room.git && cd go-ssb-room`
|
||||||
|
* [Follow the development instructions](./development.md)
|
||||||
|
* You should now have a working go-ssb-room binary! Read the HTTP Hosting section below and admin
|
||||||
|
user sections below, for more instructions on the last mile.
|
||||||
|
|
||||||
|
# HTTP Hosting
|
||||||
|
|
||||||
|
We currently assume a standard HTTPS server in front of go-ssb-room to facilitate TLS
|
||||||
|
termination and certificate management. This should be possible with most modern HTTP servers
|
||||||
|
since it's a pretty standard practice, known as [reverse
|
||||||
|
proxying](https://en.wikipedia.org/wiki/Reverse_proxy).
|
||||||
|
|
||||||
|
Two bits of rationale:
|
||||||
|
|
||||||
|
1) People usually want to have more than one site on their server. Put differently, we could
|
||||||
|
have [LetsEncrypt](https://letsencrypt.org/) inside the go-ssb-room server but it would have to
|
||||||
|
listen on port :443—blocking the use of other domains on the same IP. 2) Listening on :443 can
|
||||||
|
be pretty annoying (you might need root privileges or similar capabilities).
|
||||||
|
|
||||||
|
go-ssb-room needs three headers to function properly, which need to be forwarded by the
|
||||||
|
webserver.
|
||||||
|
|
||||||
|
* `X-Forwarded-Host` as which domain name the room is running (enforce strict TLS checking)
|
||||||
|
* `X-Forwarded-Proto` to ensure that TLS is used (and redirect if necessary)
|
||||||
|
* `X-Forwarded-For` the remote TCP/IP address of the client accessing the room (used for rate
|
||||||
|
limiting)
|
||||||
|
|
||||||
|
[example-nginx.conf](./files/example-nginx.conf) contains an [nginx](https://nginx.org) config that
|
||||||
|
we use for [hermies.club](https://hermies.club). To get a wildcard TLS certificate you can
|
||||||
|
follow the steps in [this
|
||||||
|
article](https://medium.com/@alitou/getting-a-wildcard-ssl-certificate-using-certbot-and-deploy-on-nginx-15b8ffa34157),
|
||||||
|
which uses the [certbot](https://certbot.eff.org/) utility.
|
||||||
|
|
||||||
|
# First Admin user
|
||||||
|
|
||||||
|
To manage your now working server, you need an initial admin user. For this you can use the "insert-user" utility included with go-ssb-room.
|
||||||
|
In a new terminal window navigate to the insert-user utility folder and compile the GO-based utility into an executable your computer can use
|
||||||
|
|
||||||
|
```
|
||||||
|
cd cmd/insert-user
|
||||||
|
go build
|
||||||
|
```
|
||||||
|
|
||||||
|
A new executable file should be created called "insert-user"
|
||||||
|
Execute the `./insert-user -h` command to get a full list of custom options (optional location of the repo & SQLite database and user role). follow the instructions given in the output you receive.
|
||||||
|
|
||||||
|
example (with custom repo location, only needed if you setup your with a custom repo):
|
||||||
|
|
||||||
|
```
|
||||||
|
./insert-user -repo "/ssb-go-room-secrets" "@Bp5Z5TQKv6E/Y+QZn/3LiDWMPi63EP8MHsXZ4tiIb2w=.ed25519"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can now login in the web-front-end using these credentials
|
|
@ -10,7 +10,7 @@ To build the server and see a list of its options:
|
||||||
cd cmd/server
|
cd cmd/server
|
||||||
go build
|
go build
|
||||||
./server -h
|
./server -h
|
||||||
|
|
||||||
Usage of ./server:
|
Usage of ./server:
|
||||||
-aliases-as-subdomains
|
-aliases-as-subdomains
|
||||||
needs to be disabled if a wildcard certificate for the room is not available. (default true)
|
needs to be disabled if a wildcard certificate for the room is not available. (default true)
|
||||||
|
@ -47,8 +47,8 @@ cd cmd/server && go build -tags dev && ./server
|
||||||
```
|
```
|
||||||
|
|
||||||
This can be useful if you are working on:
|
This can be useful if you are working on:
|
||||||
* the sqlite migrations,
|
* the sqlite migrations,
|
||||||
* html templates,
|
* html templates,
|
||||||
* styling elements using [tailwind](https://tailwindcss.com/docs/)
|
* styling elements using [tailwind](https://tailwindcss.com/docs/)
|
||||||
* _if you don't run generate with `-tags dev`, the bundled css will only contain the tailwind classes found in *.tmpl at the time of generation!_
|
* _if you don't run generate with `-tags dev`, the bundled css will only contain the tailwind classes found in *.tmpl at the time of generation!_
|
||||||
* or website templates or assets like JavaScript files, the favicon or other images that are used inside the HTML.
|
* or website templates or assets like JavaScript files, the favicon or other images that are used inside the HTML.
|
||||||
|
@ -73,7 +73,7 @@ cd cmd/server && go build && ./server -htts-domain my.room.example
|
||||||
|
|
||||||
This project uses [sql-migrate](https://github.com/rubenv/sql-migrate) to upgrade the sqlite database when necessary.
|
This project uses [sql-migrate](https://github.com/rubenv/sql-migrate) to upgrade the sqlite database when necessary.
|
||||||
|
|
||||||
To upgrade, create a new file in `admindb/sqlite/migrations` with your changes.
|
To upgrade, create a new file in `admindb/sqlite/migrations` with your changes.
|
||||||
|
|
||||||
**Note**: similar to the web assets, you need to use `go test -tags dev` to test them. Afterwards run, `go generate` to embed the assets in the code and thus the resulting server binary.
|
**Note**: similar to the web assets, you need to use `go test -tags dev` to test them. Afterwards run, `go generate` to embed the assets in the code and thus the resulting server binary.
|
||||||
|
|
||||||
|
@ -103,13 +103,17 @@ Aside: I would have used `sqlc` since it's a bit more minimal and uses hand writ
|
||||||
cd cmd/insert-user
|
cd cmd/insert-user
|
||||||
go build
|
go build
|
||||||
# optional step: run a script to generate a valid ssb id @<pubkey>.ed25519, useful for trying things out quickly
|
# optional step: run a script to generate a valid ssb id @<pubkey>.ed25519, useful for trying things out quickly
|
||||||
./generate-fake-id.sh
|
./generate-fake-id.sh
|
||||||
./insert-user -login <username> -key <@pubkey.ed25519>
|
./insert-user -login <username> -key <@pubkey.ed25519>
|
||||||
```
|
```
|
||||||
Then repeat your password twice and you are all set for development.
|
Then repeat your password twice and you are all set for development.
|
||||||
|
|
||||||
Run `insert-user` without any flags to see all the options.
|
Run `insert-user` without any flags to see all the options.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
For a few high-level overviews and diagrams of how the codebase works, read [architecture.md](./architecture.md).
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
See the [testing.md](./testing.md) for a thorough walkthorugh of the different testing approaches.
|
See the [testing.md](./testing.md) for a thorough walkthorugh of the different testing approaches.
|
||||||
|
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
Loading…
Reference in New Issue