Compare commits

...

23 Commits

Author SHA1 Message Date
Thomas Miceli
4c5a7bda63 v1.8.4 2024-12-16 01:46:26 +01:00
Thomas Miceli
f6bf09d5c2 Translations update from Opengist (#398)
* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (281 of 281 strings)

Translation: Opengist/Opengist
Translate-URL: http://tr.opengist.io/projects/_/opengist/zh_Hans/

* Translated using Weblate (Polish)

Currently translated at 100.0% (281 of 281 strings)

Translation: Opengist/Opengist
Translate-URL: http://tr.opengist.io/projects/_/opengist/pl/

---------

Co-authored-by: GabrielxD <gabrielxduo@outlook.com>
Co-authored-by: GGORG <GGORG0@protonmail.com>
2024-12-15 17:52:52 +01:00
Phani Rithvij
86dd59c695 fixup! esbuild for all other platforms (#395) 2024-12-15 17:52:33 +01:00
Sangelo
20aef5e694 feat: Add custom instance names (#399)
* Add custom name variable

* Add custom name variable usage to docs

* Remove leftover testing config options (oops)
2024-12-15 17:39:51 +01:00
soup
00951bf63b feat(web): prevent password manager autofill on filename inputs (#357)
* feat(web): add data-1p-ignore attribute to ignore fields

* feat(web): extend password manager ignore attributes

- Add autocomplete="off" to prevent browser autofill
- Add data-lpignore for LastPass compatibility
- Add data-bwignore for Bitwarden compatibility
2024-12-15 17:35:08 +01:00
Thomas Miceli
526da6ccbb v1.8.3 2024-11-26 22:46:25 +01:00
Phani Rithvij
3a4080176c esbuild for all other platforms (#393)
Signed-off-by: phanirithvij <phanirithvij2000@gmail.com>
2024-11-26 22:38:51 +01:00
Phani Rithvij
64306be2d6 init git config failure -> warn (#392)
* init git config failure -> warn

Signed-off-by: phanirithvij <phanirithvij2000@gmail.com>
2024-11-26 22:28:17 +01:00
Thomas Miceli
8543f3adfa v1.8.2 2024-11-25 22:29:31 +01:00
Thomas Miceli
391ffde12e Update Go deps 2024-11-25 22:20:43 +01:00
Thomas Miceli
3193a9e888 Translations update from Opengist (#373)
* Translated using Weblate (French)

Currently translated at 87.5% (245 of 280 strings)

Translation: Opengist/Opengist
Translate-URL: http://tr.opengist.io/projects/_/opengist/fr/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (280 of 280 strings)

Translation: Opengist/Opengist
Translate-URL: http://tr.opengist.io/projects/_/opengist/es/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (280 of 280 strings)

Translation: Opengist/Opengist
Translate-URL: http://tr.opengist.io/projects/_/opengist/zh_Hans/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (280 of 280 strings)

Translation: Opengist/Opengist
Translate-URL: http://tr.opengist.io/projects/_/opengist/zh_Hans/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (280 of 280 strings)

Translation: Opengist/Opengist
Translate-URL: http://tr.opengist.io/projects/_/opengist/zh_Hans/

* Added translation using Weblate (Polish)

* Translated using Weblate (Polish)

Currently translated at 100.0% (280 of 280 strings)

Translation: Opengist/Opengist
Translate-URL: http://tr.opengist.io/projects/_/opengist/pl/

---------

Co-authored-by: Lucas Colombo <lucasncolombo@gmail.com>
Co-authored-by: GabrielxD <gabrielxduo@outlook.com>
Co-authored-by: GGORG <GGORG0@protonmail.com>
2024-11-25 22:08:45 +01:00
Santhosh Raju
58c5ac11c7 Respect file scheme URIs for SQLite. (#387) 2024-11-25 22:07:13 +01:00
Thomas Miceli
6a8e827d61 Fix nits typos and translation (#388) 2024-11-23 17:41:15 +01:00
Thomas Miceli
8f482bce33 Improve Git config 2024-11-23 17:25:58 +01:00
Thomas Miceli
5994cd6ccd Enforce git config on startup (#383) 2024-11-21 11:23:57 +01:00
Thomas Miceli
00e3d09cc5 Fix escaping for embed gists (#381) 2024-11-18 02:29:05 +01:00
Thomas Miceli
40ff4c7b3f Fix git clone on SSH with MySQL (#382) 2024-11-17 21:25:59 +01:00
Thomas Miceli
c1e046f428 Convert octal notation file names in Git (#380) 2024-11-17 18:09:44 +01:00
Thomas Miceli
92bac3bf8c v1.8.1 2024-11-02 02:00:48 +01:00
Thomas Miceli
73c2fb55bc Fix confirm() popup messages (#370) 2024-11-02 01:40:10 +01:00
Thomas Miceli
75162b3ef9 Hide passkey login when login form is disabled (#369) 2024-11-02 01:06:14 +01:00
Thomas Miceli
d537153785 Fix Markdown preview (#368) 2024-11-02 01:05:43 +01:00
Thomas Miceli
97b9fa1100 Fix typos 2024-11-01 00:00:09 +01:00
44 changed files with 2653 additions and 1710 deletions

View File

@@ -1,6 +1,51 @@
# Changelog
## [1.8.0](https://github.com/thomiceli/opengist/compare/v1.7.5...v1.8.0) - 2024-09-12
## [1.8.4](https://github.com/thomiceli/opengist/compare/v1.8.3...v1.8.4) - 2024-12-15
See here how to [update](/docs/update.md) Opengist.
### Added
- More translation strings (#398)
- Custom instance names (#399)
### Fixed
- Prevent passwords managers autofill on filename inputs (#357)
## [1.8.3](https://github.com/thomiceli/opengist/compare/v1.8.2...v1.8.3) - 2024-11-26
See here how to [update](/docs/update.md) Opengist.
### Changed
- Throw `warn` instead of `fatal` on Git global config init failure (#392)
- Define esbuild as a Javascript dependency for all other platforms (#393)
## [1.8.2](https://github.com/thomiceli/opengist/compare/v1.8.1...v1.8.2) - 2024-11-25
See here how to [update](/docs/update.md) Opengist.
### Added
- More translation strings (#373) (#388)
### Changed
- Enforce git config on startup (#383)
- Respect file scheme URIs for SQLite. (#387)
### Fixed
- Convert octal notation file names in Git (#380)
- Git clone on SSH with MySQL (#382)
- Escaping for embed gists (#381)
### Other
- Update deps Golang & JS deps
## [1.8.1](https://github.com/thomiceli/opengist/compare/v1.8.0...v1.8.1) - 2024-11-02
See here how to [update](/docs/update.md) Opengist.
### Changed
- Hide passkey login when login form is disabled (#369)
### Fixed
- Markdown preview (#368)
- confirm() popup messages (#370)
## [1.8.0](https://github.com/thomiceli/opengist/compare/v1.7.5...v1.8.0) - 2024-10-31
See here how to [update](https://opengist.io/docs/update) Opengist.
### 🔴 Deprecations

View File

@@ -33,8 +33,6 @@ FROM base AS dev
EXPOSE 6157 2222 16157
VOLUME /opengist
RUN git config --global --add safe.directory /opengist
CMD ["make", "watch"]
@@ -60,7 +58,7 @@ RUN apk update && \
libstdc++
RUN addgroup -S opengist && \
adduser -S -G opengist -H -s /bin/ash -g 'Opengist User' opengist
adduser -S -G opengist -s /bin/ash -g 'Opengist User' opengist
COPY --from=build --chown=opengist:opengist /opengist/config.yml config.yml

View File

@@ -13,7 +13,7 @@ It is similar to [GitHub Gist](https://gist.github.com/), but open-source and co
![License](https://img.shields.io/github/license/thomiceli/opengist?color=blue)
[![Go CI](https://github.com/thomiceli/opengist/actions/workflows/go.yml/badge.svg)](https://github.com/thomiceli/opengist/actions/workflows/go.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/thomiceli/opengist)](https://goreportcard.com/report/github.com/thomiceli/opengist)
[![Translate](https://tr.opengist.io/widget/_/svg-badge.svg)](https://tr.opengist.io/projects/_/opengist/)
## Features
@@ -37,7 +37,7 @@ It is similar to [GitHub Gist](https://gist.github.com/), but open-source and co
Docker [images](https://github.com/thomiceli/opengist/pkgs/container/opengist) are available for each release :
```shell
docker pull ghcr.io/thomiceli/opengist:1.7
docker pull ghcr.io/thomiceli/opengist:1.8
```
It can be used in a `docker-compose.yml` file :
@@ -49,7 +49,7 @@ It can be used in a `docker-compose.yml` file :
```yml
services:
opengist:
image: ghcr.io/thomiceli/opengist:1.7
image: ghcr.io/thomiceli/opengist:1.8
container_name: opengist
restart: unless-stopped
ports:
@@ -76,9 +76,9 @@ Download the archive for your system from the release page [here](https://github
```shell
# example for linux amd64
wget https://github.com/thomiceli/opengist/releases/download/v1.8.0/opengist1.8.0-linux-amd64.tar.gz
wget https://github.com/thomiceli/opengist/releases/download/v1.8.4/opengist1.8.4-linux-amd64.tar.gz
tar xzvf opengist1.8.0-linux-amd64.tar.gz
tar xzvf opengist1.8.4-linux-amd64.tar.gz
cd opengist
chmod +x opengist
./opengist # with or without `--config config.yml`

View File

@@ -17,8 +17,8 @@ opengist-home:
# Secret key used for session store & encrypt MFA data on database. Default: <randomized 32 bytes>
secret-key:
# URI of the database. Default: opengist.db (SQLite)
# SQLite: file name
# URI of the database. Default: opengist.db (SQLite) is placed in opengist-home
# SQLite: file:/path/to/database
# PostgreSQL: postgres://user:password@host:port/database
# MySQL/MariaDB: mysql://user:password@host:port/database
db-uri: opengist.db
@@ -38,7 +38,6 @@ git.default-branch:
# For SQLite databases only.
sqlite.journal-mode: WAL
# HTTP server configuration
# Host to bind to. Default: 0.0.0.0
http.host: 0.0.0.0
@@ -72,7 +71,6 @@ ssh.external-domain:
# Path or alias to ssh-keygen executable. Default: ssh-keygen
ssh.keygen-executable: ssh-keygen
# OAuth2 configuration
# The callback/redirect URL must be http://opengist.url/oauth/<github|gitlab|gitea|openid-connect>/callback
@@ -102,6 +100,9 @@ oidc.secret:
# Discovery endpoint of the OpenID provider. Generally something like http://auth.example.com/.well-known/openid-configuration
oidc.discovery-url:
# Instance name
# Set your own custom name to be displayed instead of 'Opengist'
custom.name:
# Custom assets
# Add your own custom assets, that are files relatives to $opengist-home/custom/

View File

@@ -28,11 +28,11 @@ namespace: opengist
resources:
- namespace.yaml
- https://github.com/thomiceli/opengist/deploy/?ref:v1.8.0
- https://github.com/thomiceli/opengist/deploy/?ref:v1.8.4
images:
- name: ghcr.io/thomiceli/opengist
newTag: 1.8.0
newTag: 1.8.4
patches:
# Add your ingress

View File

@@ -19,7 +19,7 @@ export default {
<div class="mx-auto lg:text-center">
<img class="rotating h-36 mx-auto my-8 " src="https://raw.githubusercontent.com/thomiceli/opengist/master/public/opengist.svg" alt="" >
<a target="_blank" href="https://github.com/thomiceli/opengist/releases" class="inline-flex items-center rounded-full bg-indigo-100 hover:bg-indigo-200 px-4 py-1.5 text-lg font-medium text-indigo-700">
<span class="pr-1">Released 1.8.0</span>
<span class="pr-1">Released 1.8.4</span>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 19.5 15-15m0 0H8.25m11.25 0v11.25" />
</svg>

View File

@@ -37,6 +37,7 @@ aside: false
| oidc.client-key | OG_OIDC_CLIENT_KEY | none | The client key for the OpenID application. |
| oidc.secret | OG_OIDC_SECRET | none | The secret for the OpenID application. |
| oidc.discovery-url | OG_OIDC_DISCOVERY_URL | none | Discovery endpoint of the OpenID provider. |
| custom.name | OG_CUSTOM_NAME | none | The name of your instance, to be displayed in the tab title |
| custom.logo | OG_CUSTOM_LOGO | none | Path to an image, relative to $opengist-home/custom. |
| custom.favicon | OG_CUSTOM_FAVICON | none | Path to an image, relative to $opengist-home/custom. |
| custom.static-links | OG_CUSTOM_STATIC_LINK_#_(PATH,NAME) | none | Path and name to custom links, more info [here](custom-links.md). |

View File

@@ -28,4 +28,18 @@ custom.favicon: favicon.png
#### Environment variable
```sh
export OG_CUSTOM_FAVICON=favicon.png
```
```
### Instance Name
It is also possible to set a name for your instance, that would be displayed in the title bar instead of 'Opengist'.
#### YAML
```yaml
custom.name: My Gists
```
#### Environment variable
```sh
export OG_CUSTOM_NAME="My Gists"
```

View File

@@ -5,7 +5,7 @@ By default, Opengist uses SQLite as the database backend.
Because SQLite is a file-based database, there is not much configuration to tweak.
The configuration `db-uri`/`OG_DB_URI` refers to the path of the SQLite database file relative in the `$opengist-home/` directory (default `opengist.db`),
although it can be left untouched.
although it can be left untouched. You can also use an absolute path outside the `$opengist-home/` directory.
The SQLite journal mode is set to [`WAL` (Write-Ahead Logging)](https://www.sqlite.org/pragma.html#pragma_journal_mode) by default and can be changed.
@@ -14,6 +14,9 @@ The SQLite journal mode is set to [`WAL` (Write-Ahead Logging)](https://www.sqli
# default
db-uri: opengist.db
sqlite.journal-mode: WAL
# absolute path outside the $opengist-home/ directory
db-uri: file:/home/user/opengist.db
```
#### Environment variable

View File

@@ -4,9 +4,9 @@ Download the archive for your system from the release page [here](https://github
```shell
# example for linux amd64
wget https://github.com/thomiceli/opengist/releases/download/v1.8.0/opengist1.8.0-linux-amd64.tar.gz
wget https://github.com/thomiceli/opengist/releases/download/v1.8.4/opengist1.8.4-linux-amd64.tar.gz
tar xzvf opengist1.8.0-linux-amd64.tar.gz
tar xzvf opengist1.8.4-linux-amd64.tar.gz
cd opengist
chmod +x opengist
./opengist # with or without `--config config.yml`

View File

@@ -10,7 +10,7 @@ Requirements:
git clone https://github.com/thomiceli/opengist
cd opengist
git checkout v1.8.0 # optional, to checkout the latest release
git checkout v1.8.4 # optional, to checkout the latest release
make
./opengist

View File

@@ -27,9 +27,9 @@ Stop the running instance; then like your first installation of Opengist, downlo
```shell
# example for linux amd64
wget https://github.com/thomiceli/opengist/releases/download/v1.8.0/opengist1.8.0-linux-amd64.tar.gz
wget https://github.com/thomiceli/opengist/releases/download/v1.8.4/opengist1.8.4-linux-amd64.tar.gz
tar xzvf opengist1.8.0-linux-amd64.tar.gz
tar xzvf opengist1.8.4-linux-amd64.tar.gz
cd opengist
chmod +x opengist
./opengist # with or without `--config config.yml`

42
go.mod
View File

@@ -5,10 +5,10 @@ go 1.23
require (
github.com/Kunde21/markdownfmt/v3 v3.1.0
github.com/alecthomas/chroma/v2 v2.14.0
github.com/blevesearch/bleve/v2 v2.4.2
github.com/blevesearch/bleve/v2 v2.4.3
github.com/dustin/go-humanize v1.0.1
github.com/glebarez/sqlite v1.11.0
github.com/go-playground/validator/v10 v10.22.1
github.com/go-playground/validator/v10 v10.23.0
github.com/go-webauthn/webauthn v0.11.2
github.com/google/uuid v1.6.0
github.com/gorilla/securecookie v1.1.2
@@ -18,25 +18,25 @@ require (
github.com/markbates/goth v1.80.0
github.com/pquerna/otp v1.4.0
github.com/rs/zerolog v1.33.0
github.com/stretchr/testify v1.9.0
github.com/stretchr/testify v1.10.0
github.com/urfave/cli/v2 v2.27.5
github.com/yuin/goldmark v1.7.8
github.com/yuin/goldmark-emoji v1.0.4
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
go.abhg.dev/goldmark/mermaid v0.5.0
golang.org/x/crypto v0.28.0
golang.org/x/text v0.19.0
golang.org/x/crypto v0.29.0
golang.org/x/text v0.20.0
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/mysql v1.5.7
gorm.io/driver/postgres v1.5.9
gorm.io/driver/postgres v1.5.10
gorm.io/gorm v1.25.12
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/RoaringBitmap/roaring v1.9.4 // indirect
github.com/bits-and-blooms/bitset v1.14.3 // indirect
github.com/blevesearch/bleve_index_api v1.1.12 // indirect
github.com/bits-and-blooms/bitset v1.17.0 // indirect
github.com/blevesearch/bleve_index_api v1.1.13 // indirect
github.com/blevesearch/geo v0.1.20 // indirect
github.com/blevesearch/go-faiss v1.0.23 // indirect
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
@@ -46,19 +46,19 @@ require (
github.com/blevesearch/segment v0.9.1 // indirect
github.com/blevesearch/snowballstem v0.9.0 // indirect
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
github.com/blevesearch/vellum v1.0.10 // indirect
github.com/blevesearch/vellum v1.0.11 // indirect
github.com/blevesearch/zapx/v11 v11.3.10 // indirect
github.com/blevesearch/zapx/v12 v12.3.10 // indirect
github.com/blevesearch/zapx/v13 v13.3.10 // indirect
github.com/blevesearch/zapx/v14 v14.3.10 // indirect
github.com/blevesearch/zapx/v15 v15.3.15 // indirect
github.com/blevesearch/zapx/v16 v16.1.7 // indirect
github.com/blevesearch/zapx/v15 v15.3.16 // indirect
github.com/blevesearch/zapx/v16 v16.1.8 // indirect
github.com/boombuler/barcode v1.0.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.6 // indirect
github.com/gabriel-vasile/mimetype v1.4.7 // indirect
github.com/glebarez/go-sqlite v1.22.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
@@ -100,15 +100,15 @@ require (
github.com/x448/float16 v0.8.4 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
go.etcd.io/bbolt v1.3.11 // indirect
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/time v0.7.0 // indirect
google.golang.org/protobuf v1.35.1 // indirect
modernc.org/libc v1.61.0 // indirect
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/net v0.31.0 // indirect
golang.org/x/oauth2 v0.24.0 // indirect
golang.org/x/sync v0.9.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/time v0.8.0 // indirect
google.golang.org/protobuf v1.35.2 // indirect
modernc.org/libc v1.61.2 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/sqlite v1.33.1 // indirect
modernc.org/sqlite v1.34.1 // indirect
)

104
go.sum
View File

@@ -13,12 +13,12 @@ github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bits-and-blooms/bitset v1.14.3 h1:Gd2c8lSNf9pKXom5JtD7AaKO8o7fGQ2LtFj1436qilA=
github.com/bits-and-blooms/bitset v1.14.3/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/blevesearch/bleve/v2 v2.4.2 h1:NooYP1mb3c0StkiY9/xviiq2LGSaE8BQBCc/pirMx0U=
github.com/blevesearch/bleve/v2 v2.4.2/go.mod h1:ATNKj7Yl2oJv/lGuF4kx39bST2dveX6w0th2FFYLkc8=
github.com/blevesearch/bleve_index_api v1.1.12 h1:P4bw9/G/5rulOF7SJ9l4FsDoo7UFJ+5kexNy1RXfegY=
github.com/blevesearch/bleve_index_api v1.1.12/go.mod h1:PbcwjIcRmjhGbkS/lJCpfgVSMROV6TRubGGAODaK1W8=
github.com/bits-and-blooms/bitset v1.17.0 h1:1X2TS7aHz1ELcC0yU1y2stUs/0ig5oMU6STFZGrhvHI=
github.com/bits-and-blooms/bitset v1.17.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/blevesearch/bleve/v2 v2.4.3 h1:XDYj+1prgX84L2Cf+V3ojrOPqXxy0qxyd2uLMmeuD+4=
github.com/blevesearch/bleve/v2 v2.4.3/go.mod h1:hEPDPrbYw3vyrm5VOa36GyS4bHWuIf4Fflp7460QQXY=
github.com/blevesearch/bleve_index_api v1.1.13 h1:+nrA6oRJr85aCPyqaeZtsruObwKojutfonHJin/BP48=
github.com/blevesearch/bleve_index_api v1.1.13/go.mod h1:PbcwjIcRmjhGbkS/lJCpfgVSMROV6TRubGGAODaK1W8=
github.com/blevesearch/geo v0.1.20 h1:paaSpu2Ewh/tn5DKn/FB5SzvH0EWupxHEIwbCk/QPqM=
github.com/blevesearch/geo v0.1.20/go.mod h1:DVG2QjwHNMFmjo+ZgzrIq2sfCh6rIHzy9d9d0B59I6w=
github.com/blevesearch/go-faiss v1.0.23 h1:Wmc5AFwDLKGl2L6mjLX1Da3vCL0EKa2uHHSorcIS1Uc=
@@ -37,8 +37,8 @@ github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD
github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs=
github.com/blevesearch/upsidedown_store_api v1.0.2 h1:U53Q6YoWEARVLd1OYNc9kvhBMGZzVrdmaozG2MfoB+A=
github.com/blevesearch/upsidedown_store_api v1.0.2/go.mod h1:M01mh3Gpfy56Ps/UXHjEO/knbqyQ1Oamg8If49gRwrQ=
github.com/blevesearch/vellum v1.0.10 h1:HGPJDT2bTva12hrHepVT3rOyIKFFF4t7Gf6yMxyMIPI=
github.com/blevesearch/vellum v1.0.10/go.mod h1:ul1oT0FhSMDIExNjIxHqJoGpVrBpKCdgDQNxfqgJt7k=
github.com/blevesearch/vellum v1.0.11 h1:SJI97toEFTtA9WsDZxkyGTaBWFdWl1n2LEDCXLCq/AU=
github.com/blevesearch/vellum v1.0.11/go.mod h1:QgwWryE8ThtNPxtgWJof5ndPfx0/YMBh+W2weHKPw8Y=
github.com/blevesearch/zapx/v11 v11.3.10 h1:hvjgj9tZ9DeIqBCxKhi70TtSZYMdcFn7gDb71Xo/fvk=
github.com/blevesearch/zapx/v11 v11.3.10/go.mod h1:0+gW+FaE48fNxoVtMY5ugtNHHof/PxCqh7CnhYdnMzQ=
github.com/blevesearch/zapx/v12 v12.3.10 h1:yHfj3vXLSYmmsBleJFROXuO08mS3L1qDCdDK81jDl8s=
@@ -47,10 +47,10 @@ github.com/blevesearch/zapx/v13 v13.3.10 h1:0KY9tuxg06rXxOZHg3DwPJBjniSlqEgVpxIq
github.com/blevesearch/zapx/v13 v13.3.10/go.mod h1:w2wjSDQ/WBVeEIvP0fvMJZAzDwqwIEzVPnCPrz93yAk=
github.com/blevesearch/zapx/v14 v14.3.10 h1:SG6xlsL+W6YjhX5N3aEiL/2tcWh3DO75Bnz77pSwwKU=
github.com/blevesearch/zapx/v14 v14.3.10/go.mod h1:qqyuR0u230jN1yMmE4FIAuCxmahRQEOehF78m6oTgns=
github.com/blevesearch/zapx/v15 v15.3.15 h1:JydcGIq279tmTrfBBSPDF/VOiCMBLQ+rJulTXrGFlGA=
github.com/blevesearch/zapx/v15 v15.3.15/go.mod h1:Turk/TNRKj9es7ZpKK95PS7f6D44Y7fAFy8F4LXQtGg=
github.com/blevesearch/zapx/v16 v16.1.7 h1:I07qV6l1rPda19zyof9Q2J9E8cjZ57pQhNY0+ePI5vM=
github.com/blevesearch/zapx/v16 v16.1.7/go.mod h1:JqQlOqlRVaYDkpLIl3JnKql8u4zKTNlVEa3nLsi0Gn8=
github.com/blevesearch/zapx/v15 v15.3.16 h1:Ct3rv7FUJPfPk99TI/OofdC+Kpb4IdyfdMH48sb+FmE=
github.com/blevesearch/zapx/v15 v15.3.16/go.mod h1:Turk/TNRKj9es7ZpKK95PS7f6D44Y7fAFy8F4LXQtGg=
github.com/blevesearch/zapx/v16 v16.1.8 h1:Bxzpw6YQpFs7UjoCV1+RvDw6fmAT2GZxldwX8b3wVBM=
github.com/blevesearch/zapx/v16 v16.1.8/go.mod h1:JqQlOqlRVaYDkpLIl3JnKql8u4zKTNlVEa3nLsi0Gn8=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/boombuler/barcode v1.0.2 h1:79yrbttoZrLGkL/oOI8hBrUKucwOL0oOjUgEguGMcJ4=
github.com/boombuler/barcode v1.0.2/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
@@ -75,8 +75,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc=
github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc=
github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA=
github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU=
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
@@ -87,8 +87,8 @@ 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.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA=
github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
@@ -212,8 +212,8 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
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/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
@@ -236,34 +236,34 @@ go.abhg.dev/goldmark/mermaid v0.5.0 h1:mDkykpSPJ+5wCQ8bSXgzJ2KQskjXkI5Ndxz7JYDHW
go.abhg.dev/goldmark/mermaid v0.5.0/go.mod h1:OCyk2o85TX2drWHH+HRy6bih2yZlUwbbv/R1MMh1YLs=
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
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.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
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/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
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/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -272,21 +272,21 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8=
gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/driver/postgres v1.5.10 h1:7Lggqempgy496c0WfHXsYWxk3Th+ZcW66/21QhVFdeE=
gorm.io/driver/postgres v1.5.10/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v4 v4.21.0 h1:kKPI3dF7RIag8YcToh5ZwDcVMIv6VGa0ED5cvh0LMW4=
modernc.org/ccgo/v4 v4.21.0/go.mod h1:h6kt6H/A2+ew/3MW/p6KEoQmrq/i3pr0J/SiwiaF/g0=
modernc.org/cc/v4 v4.23.1 h1:WqJoPL3x4cUufQVHkXpXX7ThFJ1C4ik80i2eXEXbhD8=
modernc.org/cc/v4 v4.23.1/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v4 v4.22.3 h1:C7AW89Zw3kygesTQWBzApwIn9ldM+cb/plrTIKq41Os=
modernc.org/ccgo/v4 v4.22.3/go.mod h1:Dz7n0/UkBbH3pnYaxgi1mFSfF4REqUOZNziphZASx6k=
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.5.0 h1:bJ9ChznK1L1mUtAQtxi0wi5AtAs5jQuw4PrPHO5pb6M=
modernc.org/gc/v2 v2.5.0/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
modernc.org/libc v1.61.0 h1:eGFcvWpqlnoGwzZeZe3PWJkkKbM/3SUGyk1DVZQ0TpE=
modernc.org/libc v1.61.0/go.mod h1:DvxVX89wtGTu+r72MLGhygpfi3aUGgZRdAYGCAVVud0=
modernc.org/libc v1.61.2 h1:dkO4DlowfClcJYsvf/RiK6fUwvzCQTmB34bJLt0CAGQ=
modernc.org/libc v1.61.2/go.mod h1:4QGjNyX3h+rn7V5oHpJY2yH0QN6frt1X+5BkXzwLPCo=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
@@ -295,8 +295,8 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM=
modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k=
modernc.org/sqlite v1.34.1 h1:u3Yi6M0N8t9yKRDwhXcyp1eS5/ErhPTBggxWFuR6Hfk=
modernc.org/sqlite v1.34.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k=
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=

View File

@@ -37,7 +37,7 @@ var CmdStart = cli.Command{
Initialize(ctx)
go web.NewServer(os.Getenv("OG_DEV") == "1", path.Join(config.GetHomeDir(), "sessions")).Start()
go web.NewServer(os.Getenv("OG_DEV") == "1", path.Join(config.GetHomeDir(), "sessions"), false).Start()
go ssh.Start()
<-stopCtx.Done()
@@ -95,6 +95,10 @@ func Initialize(ctx *cli.Context) {
homePath := config.GetHomeDir()
log.Info().Msg("Data directory: " + homePath)
if err := git.InitGitConfig(); err != nil {
log.Warn().Err(err).Msgf("Failed to change the host's git global config, ensure to add to `safe.directory` the path %s, and `receive.advertisePushOptions` is set to true.", homePath)
}
if err := createSymlink(homePath, ctx.String("config")); err != nil {
log.Fatal().Err(err).Msg("Failed to create symlinks")
}

View File

@@ -71,6 +71,7 @@ type config struct {
OIDCSecret string `yaml:"oidc.secret" env:"OG_OIDC_SECRET"`
OIDCDiscoveryUrl string `yaml:"oidc.discovery-url" env:"OG_OIDC_DISCOVERY_URL"`
CustomName string `yaml:"custom.name" env:"OG_CUSTOM_NAME"`
CustomLogo string `yaml:"custom.logo" env:"OG_CUSTOM_LOGO"`
CustomFavicon string `yaml:"custom.favicon" env:"OG_CUSTOM_FAVICON"`
StaticLinks []StaticLink `yaml:"custom.static-links" env:"OG_CUSTOM_STATIC_LINK"`

View File

@@ -19,7 +19,7 @@ const (
func GetSetting(key string) (string, error) {
var setting AdminSetting
err := db.Where("key = ?", key).First(&setting).Error
err := db.Where("`key` = ?", key).First(&setting).Error
return setting.Value, err
}

View File

@@ -46,25 +46,24 @@ var DatabaseInfo *databaseInfo
func parseDBURI(uri string) (*databaseInfo, error) {
info := &databaseInfo{}
if !strings.Contains(uri, "://") {
info.Type = SQLite
if uri == "file::memory:" {
info.Database = "file::memory:"
return info, nil
}
info.Database = filepath.Join(config.GetHomeDir(), uri)
return info, nil
}
u, err := url.Parse(uri)
if err != nil {
return nil, fmt.Errorf("invalid URI: %v", err)
}
if u.Scheme == "" {
info.Type = SQLite
info.Database = filepath.Join(config.GetHomeDir(), uri)
return info, nil
}
switch u.Scheme {
case "postgres", "postgresql":
info.Type = PostgreSQL
case "mysql", "mariadb":
info.Type = MySQL
case "file":
info.Type = SQLite
default:
return nil, fmt.Errorf("unknown database: %v", err)
}
@@ -83,6 +82,8 @@ func parseDBURI(uri string) (*databaseInfo, error) {
switch info.Type {
case PostgreSQL, MySQL:
info.Database = strings.TrimPrefix(u.Path, "/")
case SQLite:
info.Database = u.String()
default:
return nil, fmt.Errorf("unknown database: %v", err)
}
@@ -190,12 +191,21 @@ func setupSQLite(dbInfo databaseInfo, sharedCache bool) error {
log.Warn().Msg("Invalid SQLite journal mode: " + journalMode)
}
sharedCacheStr := ""
if sharedCache {
sharedCacheStr = "&cache=shared"
u, err := url.Parse(dbInfo.Database)
if err != nil {
return err
}
db, err = gorm.Open(sqlite.Open(dbInfo.Database+"?_fk=true&_journal_mode="+journalMode+sharedCacheStr), &gorm.Config{
u.Scheme = "file"
q := u.Query()
q.Set("_fk", "true")
q.Set("_journal_mode", journalMode)
if sharedCache {
q.Set("cache", "shared")
}
u.RawQuery = q.Encode()
dsn := u.String()
db, err = gorm.Open(sqlite.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
TranslateError: true,
})

View File

@@ -6,6 +6,7 @@ import (
"context"
"fmt"
"io"
"net/url"
"os"
"os/exec"
"path"
@@ -115,6 +116,9 @@ func GetFilesOfRepository(user string, gist string, revision string) ([]string,
}
slice := strings.Split(string(stdout), "\n")
for i, s := range slice {
slice[i] = convertOctalToUTF8(s)
}
return slice[:len(slice)-1], nil
}
@@ -153,7 +157,7 @@ func CatFileBatch(user string, gist string, revision string, truncate bool) ([]*
fileMap = append(fileMap, &catFileBatch{
Hash: hash,
Size: size,
Name: name,
Name: convertOctalToUTF8(name),
})
}
@@ -249,7 +253,7 @@ func GetFileContent(user string, gist string, revision string, filename string,
"git",
"--no-pager",
"show",
revision+":"+filename,
revision+":"+convertURLToOctal(filename),
)
cmd.Dir = repositoryPath
@@ -273,7 +277,7 @@ func GetFileSize(user string, gist string, revision string, filename string) (ui
"git",
"cat-file",
"-s",
revision+":"+filename,
revision+":"+convertURLToOctal(filename),
)
cmd.Dir = repositoryPath
@@ -565,6 +569,48 @@ func removeFilesExceptGit(dir string) error {
})
}
func convertOctalToUTF8(name string) string {
name = strings.Trim(name, `"`)
utf8Name, err := strconv.Unquote(name)
if err != nil {
utf8Name, err = strconv.Unquote(`"` + name + `"`)
if err != nil {
return name
}
}
return utf8Name
}
func convertUTF8ToOctal(name string) string {
if strings.Contains(name, "\\") {
return name
}
needsQuoting := false
for _, r := range name {
if r > 127 {
needsQuoting = true
break
}
}
if !needsQuoting {
return name
}
quoted := fmt.Sprintf("%q", name)
return strings.Trim(quoted, `"`)
}
func convertURLToOctal(name string) string {
decoded, err := url.QueryUnescape(name)
if err != nil {
return name
}
return convertUTF8ToOctal(decoded)
}
const hookTemplate = `#!/bin/sh
"$OG_OPENGIST_HOME_INTERNAL/symlinks/opengist" --config=$OG_OPENGIST_HOME_INTERNAL/symlinks/config.yml hook %s
`

View File

@@ -61,11 +61,12 @@ func TestContent(t *testing.T) {
"my_other_file.txt": `I really
hate Opengist`,
"rip.txt": "byebye",
"中文名.txt": "中文内容",
})
files, err := GetFilesOfRepository("thomas", "gist1", "HEAD")
require.NoError(t, err, "Could not get files of repository")
require.Subset(t, []string{"my_file.txt", "my_other_file.txt", "rip.txt"}, files, "Files are not correct")
require.Subset(t, []string{"my_file.txt", "my_other_file.txt", "rip.txt", "中文名.txt"}, files, "Files are not correct")
content, truncated, err := GetFileContent("thomas", "gist1", "HEAD", "my_file.txt", false)
require.NoError(t, err, "Could not get content")
@@ -77,16 +78,22 @@ hate Opengist`,
require.False(t, truncated, "Content should not be truncated")
require.Equal(t, "I really\nhate Opengist", content, "Content is not correct")
content, truncated, err = GetFileContent("thomas", "gist1", "HEAD", "中文名.txt", false)
require.NoError(t, err, "Could not get content")
require.False(t, truncated, "Content should not be truncated")
require.Equal(t, "中文内容", content, "Content is not correct")
CommitToBare(t, "thomas", "gist1", map[string]string{
"my_renamed_file.txt": "I love Opengist\n",
"my_other_file.txt": `I really
like Opengist actually`,
"new_file.txt": "Wait now there is a new file",
"中文名.txt": "中文内容",
})
files, err = GetFilesOfRepository("thomas", "gist1", "HEAD")
require.NoError(t, err, "Could not get files of repository")
require.Subset(t, []string{"my_renamed_file.txt", "my_other_file.txt", "new_file.txt"}, files, "Files are not correct")
require.Subset(t, []string{"my_renamed_file.txt", "my_other_file.txt", "new_file.txt", "中文名.txt"}, files, "Files are not correct")
content, truncated, err = GetFileContent("thomas", "gist1", "HEAD", "my_other_file.txt", false)
require.NoError(t, err, "Could not get content")

63
internal/git/config.go Normal file
View File

@@ -0,0 +1,63 @@
package git
import (
"errors"
"os/exec"
"regexp"
)
type configEntry struct {
value string
fn func(string, string) error
}
func InitGitConfig() error {
configs := map[string]configEntry{
"receive.advertisePushOptions": {value: "true", fn: setGitConfig},
"safe.directory": {value: "*", fn: addGitConfig},
}
for key, entry := range configs {
if err := entry.fn(key, entry.value); err != nil {
return err
}
}
return nil
}
func setGitConfig(key, value string) error {
_, err := getGitConfig(key, value)
if err != nil && !checkErrorCode(err, 1) {
return err
}
cmd := exec.Command("git", "config", "--global", key, value)
return cmd.Run()
}
func addGitConfig(key, value string) error {
_, err := getGitConfig(key, regexp.QuoteMeta(value))
if err == nil {
return nil
}
if checkErrorCode(err, 1) {
cmd := exec.Command("git", "config", "--global", "--add", key, value)
return cmd.Run()
}
return err
}
func getGitConfig(key, value string) (string, error) {
cmd := exec.Command("git", "config", "--global", "--get", key, value)
out, err := cmd.Output()
return string(out), err
}
func checkErrorCode(err error, code int) bool {
var exitError *exec.ExitError
if errors.As(err, &exitError) {
return exitError.ExitCode() == code
}
return false
}

View File

@@ -193,28 +193,28 @@ loopLog:
case strings.HasPrefix(line, "dissimilarity index"):
continue
case strings.HasPrefix(line, "rename from "):
currentFile.OldFilename = line[12 : len(line)-1]
currentFile.OldFilename = convertOctalToUTF8(line[12 : len(line)-1])
case strings.HasPrefix(line, "rename to "):
currentFile.Filename = line[10 : len(line)-1]
currentFile.Filename = convertOctalToUTF8(line[10 : len(line)-1])
parseRename = false
case strings.HasPrefix(line, "copy from "):
currentFile.OldFilename = line[10 : len(line)-1]
currentFile.OldFilename = convertOctalToUTF8(line[10 : len(line)-1])
case strings.HasPrefix(line, "copy to "):
currentFile.Filename = line[8 : len(line)-1]
currentFile.Filename = convertOctalToUTF8(line[8 : len(line)-1])
parseRename = false
case strings.HasPrefix(line, "new file"):
currentFile.IsCreated = true
case strings.HasPrefix(line, "deleted file"):
currentFile.IsDeleted = true
case strings.HasPrefix(line, "--- "):
name := line[4 : len(line)-1]
name := convertOctalToUTF8(line[4 : len(line)-1])
if parseRename && currentFile.IsDeleted {
currentFile.Filename = name[2:]
} else if parseRename && strings.HasPrefix(name, "a/") {
currentFile.OldFilename = name[2:]
}
case strings.HasPrefix(line, "+++ "):
name := line[4 : len(line)-1]
name := convertOctalToUTF8(line[4 : len(line)-1])
if parseRename && strings.HasPrefix(name, "b/") {
currentFile.Filename = name[2:]
}

View File

@@ -52,6 +52,7 @@ gist.edit.change-visibility: Make
gist.edit.delete: Delete
gist.edit.cancel: Cancel
gist.edit.save: Save
gist.delete.confirm: Are you sure you want to delete this gist ?
gist.list.joined: Joined
gist.list.all: All gists
@@ -260,6 +261,7 @@ admin.invitations.code: Code
admin.invitations.copy_link: Copy link
admin.invitations.uses: Uses
admin.invitations.expired: Expired
admin.invitations.delete_confirm: Do you want to delete this invitation ?
flash.admin.user-deleted: User has been deleted
flash.admin.gist-deleted: Gist has been deleted

View File

@@ -17,8 +17,8 @@ gist.header.clone-http: Clonar via %s
gist.header.clone-http-help: Clonar con Git usando autenticación básica HTTP.
gist.header.clone-ssh: Clonar via SSH
gist.header.clone-ssh-help: Clonar con Git usando una clave SSH.
gist.header.embed: ''
gist.header.embed-help: ''
gist.header.embed: 'Embeber'
gist.header.embed-help: 'Embebe este gist en tu sitio web.'
gist.header.download-zip: Descargar ZIP
gist.raw: Sin formato
@@ -71,8 +71,8 @@ gist.forks: Bifurcaciones
gist.forks.view: Ver bifurcación
gist.forks.no: No hay bifurcaciones públicas
gist.likes: Gustos
gist.likes.no: Aún no hay gustos
gist.likes: Todos los me gusta
gist.likes.no: Aún no hay me gusta
gist.revisions: Revisiones
gist.revision.revised: revisó este gist
@@ -80,7 +80,7 @@ gist.revision.go-to-revision: Ir a la revisión
gist.revision.file-created: archivo creado
gist.revision.file-deleted: archivo eliminado
gist.revision.file-renamed: renombrado a
gist.revision.diff-truncated: Diferencia truncada porque es demasiado grande para mostrarse.
gist.revision.diff-truncated: Diferencia truncada porque es demasiado grande para mostrarse
gist.revision.file-renamed-no-changes: Archivo renombrado sin cambios
gist.revision.empty-file: Archivo vacío
gist.revision.no-changes: Sin cambios
@@ -165,8 +165,8 @@ admin.disable-login: Deshabilitar formulario de inicio de sesión
admin.disable-login_help: Prohibir el inicio de sesión a través del formulario de inicio de sesión para forzar el uso de proveedores de OAuth en su lugar.
admin.disable-gravatar: Deshabilitar Gravatar
admin.disable-gravatar_help: Deshabilitar el uso de Gravatar como proveedor de avatar.
admin.allow-gists-without-login:
admin.allow-gists-without-login_help:
admin.allow-gists-without-login: Permitir gists individuales sin iniciar sesión
admin.allow-gists-without-login_help: Permitir ver y descargar gists individuales sin iniciar sesión, requiriendo iniciar sesión para descubrir gists.
admin.users.delete_confirm: ¿Quieres eliminar a este usuario?
admin.gists.title: Título
@@ -174,86 +174,123 @@ admin.gists.private: ¿Privado?
admin.gists.nb-files: Núm. de archivos
admin.gists.nb-likes: Núm. de gustos
admin.gists.delete_confirm: ¿Quieres eliminar este gist?
gist.new.url: ''
gist.new.preview: ''
gist.new.create-a-new-gist: ''
gist.edit.edit-gist: ''
gist.list.all-liked-by: ''
gist.list.all-forked-by: ''
gist.list.all-from: ''
gist.search.found: ''
gist.search.no-results: ''
gist.search.help.user: ''
gist.search.help.title: ''
gist.search.help.filename: ''
gist.search.help.extension: ''
gist.search.help.language: ''
gist.forks.for: ''
gist.likes.for: ''
gist.revision-of: ''
settings.link-gitlab-account: ''
settings.unlink-gitlab-account: ''
settings.change-username: ''
settings.create-password: ''
settings.create-password-help: ''
settings.change-password: ''
settings.change-password-help: ''
settings.password-label-title: ''
error.page-not-found: ''
error.bad-request: ''
error.signup-disabled: ''
error.signup-disabled-form: ''
error.login-disabled-form: ''
error.complete-oauth-login: ''
error.oauth-unsupported: ''
error.cannot-bind-data: ''
error.invalid-number: ''
error.invalid-character-unescaped: ''
admin.invitations: ''
admin.invitations.create: ''
admin.actions.sync-previews: ''
admin.actions.reset-hooks: ''
admin.actions.index-gists: ''
admin.config-link-overriden: ''
admin.invitations.help: ''
admin.invitations.max_uses: ''
admin.invitations.expires_at: ''
admin.invitations.code: ''
admin.invitations.copy_link: ''
admin.invitations.uses: ''
admin.invitations.expired: ''
flash.admin.user-deleted: ''
flash.admin.gist-deleted: ''
flash.admin.invitation-created: ''
flash.admin.invitation-deleted: ''
flash.admin.sync-fs: ''
flash.admin.sync-db: ''
flash.admin.git-gc: ''
flash.admin.sync-previews: ''
flash.admin.reset-hooks: ''
flash.admin.index-gists: ''
flash.auth.username-exists: ''
flash.auth.invalid-credentials: ''
flash.auth.account-linked-oauth: ''
flash.auth.account-unlinked-oauth: ''
flash.auth.user-sshkeys-not-retrievable: ''
flash.auth.user-sshkeys-not-created: ''
flash.auth.must-be-logged-in: ''
flash.gist.visibility-changed: ''
flash.gist.deleted: ''
flash.gist.fork-own-gist: ''
flash.gist.forked: ''
flash.user.email-updated: ''
flash.user.invalid-ssh-key: ''
flash.user.ssh-key-added: ''
flash.user.ssh-key-deleted: ''
flash.user.password-updated: ''
flash.user.username-updated: ''
validation.is-too-long: ''
validation.should-not-be-empty: ''
validation.should-not-include-sub-directory: ''
validation.should-only-contain-alphanumeric-characters: ''
validation.should-only-contain-alphanumeric-characters-and-dashes: ''
validation.not-enough: ''
validation.invalid: ''
html.title.admin-panel: ''
gist.new.url: 'URL'
gist.new.preview: 'Previsualizar'
gist.new.create-a-new-gist: 'Crear un nuevo gist'
gist.edit.edit-gist: 'Editar %s'
gist.list.all-liked-by: 'Todos los gists que le gustaron a %s'
gist.list.all-forked-by: 'Todos los gists bifurcados por %s'
gist.list.all-from: 'Todos los gists de %s'
gist.search.found: 'gists encontrados'
gist.search.no-results: 'No se han encontrado gists'
gist.search.help.user: 'gists creados por el usuario'
gist.search.help.title: 'gists con el título indicado'
gist.search.help.filename: 'gists que contienen archivos con el nombre indicado'
gist.search.help.extension: 'gists que contienen archivos con la extensión indicada'
gist.search.help.language: 'gists que contienen archivos con el lenguaje indicado'
gist.forks.for: 'Bifurcacaiones de %s'
gist.likes.for: 'Me gusta para %s'
gist.revision-of: 'Revisión de %s'
settings.link-gitlab-account: 'Vincular cuenta de GitLab'
settings.unlink-gitlab-account: 'Desvincular cuenta de GitLab'
settings.change-username: 'Cambiar nombre de usuario'
settings.create-password: 'Crear contraseña'
settings.create-password-help: 'Crea tu contraseña para acceder a Opengist vía HTTP'
settings.change-password: 'Cambiar contraseña'
settings.change-password-help: 'Cambia tu contraseña para acceder a Opengist vía HTTP'
settings.password-label-title: 'Contraseña'
error.page-not-found: 'Página no encontrada'
error.bad-request: 'Solicitud incorrecta'
error.signup-disabled: 'El registro está deshabilitado'
error.signup-disabled-form: 'El registro mediante el formulario está deshabilitado'
error.login-disabled-form: 'El inicio de sesión mediante el formulario está deshabilitado'
error.complete-oauth-login: 'No se puede completar la autenticación del usuario: %s'
error.oauth-unsupported: 'Proveedor no compatible'
error.cannot-bind-data: 'No se puede vincular los datos'
error.invalid-number: 'Número inválido'
error.invalid-character-unescaped: 'Carácter inválido no escapado'
admin.invitations: 'Invitaciones'
admin.invitations.create: 'Crear invitación'
admin.actions.sync-previews: 'Sincronizar todas las vistas previas de gists'
admin.actions.reset-hooks: 'Resetear los hooks de Git en todos los repositorios'
admin.actions.index-gists: 'Indexar todos los gists'
admin.config-link-overriden: 'sobrescrito'
admin.invitations.help: 'Las invitaciones se pueden usar para crear una cuenta aunque el registro esté deshabilitado.'
admin.invitations.max_uses: 'Cantidad máxima de usos'
admin.invitations.expires_at: 'Expira el'
admin.invitations.code: 'Código'
admin.invitations.copy_link: 'Copiar vínculo'
admin.invitations.uses: 'Usos'
admin.invitations.expired: 'Expirado'
flash.admin.user-deleted: 'El usuario ha sido eliminado'
flash.admin.gist-deleted: 'El gist ha sido eliminado'
flash.admin.invitation-created: 'La invitación ha sido creada'
flash.admin.invitation-deleted: 'La invitación ha sido eliminada'
flash.admin.sync-fs: 'Sincronizando repositorios desde el sistema de archivos...'
flash.admin.sync-db: 'Sincronizando repositorios desde la base de datos...'
flash.admin.git-gc: 'Recolectando basura en los repositorios...'
flash.admin.sync-previews: 'Sincronizando vistas previas de gists...'
flash.admin.reset-hooks: 'Reseteando hooks del servidor Git en todos los repositorios...'
flash.admin.index-gists: 'Indexando todos los gists...'
flash.auth.username-exists: 'El nombre de usuario ya existe'
flash.auth.invalid-credentials: 'Credenciales incorrectas'
flash.auth.account-linked-oauth: 'Cuenta vinculada a %s'
flash.auth.account-unlinked-oauth: 'Cuenta desvinculada de %s'
flash.auth.user-sshkeys-not-retrievable: 'No se pudo obtener las claves del usuario'
flash.auth.user-sshkeys-not-created: 'No se pudo crear la aclave ssh'
flash.auth.must-be-logged-in: 'Debes estar logueaado para acceder a los gists'
flash.gist.visibility-changed: 'La visibilidad del Gist ha sido modificada'
flash.gist.deleted: 'El gist fue eliminado'
flash.gist.fork-own-gist: 'No se puede bifurcar gists propios'
flash.gist.forked: 'El gist ha sido bifurcado'
flash.user.email-updated: 'Correo actualizado'
flash.user.invalid-ssh-key: 'Clave SSH inválida'
flash.user.ssh-key-added: 'Clave SSH añadida'
flash.user.ssh-key-deleted: 'Clave SSH eliminada'
flash.user.password-updated: 'Contraseña actualizada'
flash.user.username-updated: 'Nombre de usuario actualizado'
validation.is-too-long: 'El campo %s es demasiado largo'
validation.should-not-be-empty: 'El campo %s no puede estar vacío'
validation.should-not-include-sub-directory: 'El campo %s no puede incluir un sub directorio'
validation.should-only-contain-alphanumeric-characters: 'El campo %s solo puede contener caracteres alfanuméricos'
validation.should-only-contain-alphanumeric-characters-and-dashes: 'El campo %s solo puede contener caracteres alfanuméricos y guiones'
validation.not-enough: 'No hay suficiente %s'
validation.invalid: '%s inválido'
html.title.admin-panel: 'Panel de administración'
auth.mfa: Autenticación mult-factor
auth.mfa.passkey: Clave de acceso
auth.mfa.passkeys: Claves de acceso
auth.mfa.use-passkey: Utilizar clave de acceso
auth.mfa.bind-passkey: Vincular clave de acceso
auth.mfa.login-with-passkey: Ingresar con clave de acceso
auth.mfa.waiting-for-passkey-input: Esperando interacción del navegador...
auth.mfa.use-passkey-to-finish: Usa una clave de acceso para completar la autenticación
auth.mfa.passkeys-help: Agrega una clave de acceso para iniciar sesión en tu cuenta y usarla como método MFA.
auth.mfa.passkey-name: Nombre
auth.mfa.delete-passkey: Eliminar
auth.mfa.passkey-added-at: Agregado
auth.mfa.passkey-never-used: Nunca utilizado
auth.mfa.passkey-last-used: Último uso
auth.mfa.delete-passkey-confirm: Confirmar eliminación de clave de acceso
auth.totp.enter-recovery-key: o una clave de recuperación si perdiste tu dispositivo
auth.totp.code: Código
auth.totp.submit: Enviar
auth.totp.proceed: Proceder
auth.totp.save-recovery-codes: Guarda tus códigos de recuperación en un lugar seguro. Puedes usarlos para recuperar el acceso a tu cuenta si pierdes el acceso a tu app de autenticación.
auth.totp.scan-qr-code: Escanea el código QR con tu app de autenticación para habilitar la autenticación de doble factor o ingresa la siguiente cadena y confirma con el código generado.
error.not-in-mfa-session: El usuario no está en una sesión MFA
settings.ssh-key-exists: La clave SSH ya existe
auth.totp: Contraseña de un solo uso basada en tiempo (TOTP)
auth.totp.help: TOTP es un método de autenticación doble factor que utiliza una clave compartida para generar una contraseña de un solo uso.
auth.totp.use: Usar TOTP
auth.totp.regenerate-recovery-codes: Regenerar códigos de recuperación
auth.totp.already-enabled: TOTP ya está habilitado
auth.totp.invalid-secret: Clave TOTP inválido
auth.totp.invalid-code: Código TOTP inválido
auth.totp.code-used: El código de recuperación %s fue utilizado, ahora es inválido. Puedes desactivar MFA por ahora o regenerar tus códigos.
auth.totp.disabled: TOTP deshabilitado exitosamente
auth.totp.disable: Deshabilitar TOTP
auth.totp.enter-code: Ingresa el código de la app de autenticación
gist.delete.confirm: ¿Estás seguro que deseas eliminar este gist?
flash.auth.passkey-registred: Clave de acceso %s registrada
flash.auth.passkey-deleted: Clave de acceso eliminada

View File

@@ -258,3 +258,4 @@ validation.not-enough: 'Pas assez de %s'
validation.invalid: '%s non valide'
html.title.admin-panel: 'Administration'
settings.ssh-key-exists: La clé SSH existe déjà
gist.delete.confirm: Voulez-vous supprimer ce Gist ?

View File

@@ -0,0 +1,307 @@
gist.public: 'Publiczny'
gist.unlisted: 'Niepubliczny'
gist.private: 'Prywatny'
gist.header.like: 'Polub'
gist.header.unlike: 'Cofnij polubienie'
gist.header.fork: 'Zforkuj'
gist.header.edit: 'Edytuj'
gist.header.delete: 'Usuń'
gist.header.forked-from: 'Zforkowane z'
gist.header.last-active: 'Ostatnio aktywny'
gist.header.select-tab: 'Wybierz kartę'
gist.header.code: 'Kod'
gist.header.revisions: 'Rewizje'
gist.header.revision: 'Rewizja'
gist.header.clone-http: 'Sklonuj za pomocą %s'
gist.header.clone-http-help: 'Sklonuj za pomocą Git używając podstawowej autoryzacji HTTP.'
gist.header.clone-ssh: 'Sklonuj za pomocą SSH'
gist.header.clone-ssh-help: 'Sklonuj za pomocą Git używając klucza SSH.'
gist.header.embed: 'Osadź'
gist.header.embed-help: 'Wstaw ten Gist na twoją stronę.'
gist.header.download-zip: 'Pobierz ZIP'
gist.raw: 'Surowy'
gist.file-truncated: 'Ten plik został przycięty.'
gist.watch-full-file: 'Zobacz pełny plik.'
gist.file-not-valid: 'Ten plik nie jest poprawnym plikiem CSV.'
gist.no-content: 'Nie znaleziono plików'
gist.new.new_gist: 'Nowy Gist'
gist.new.title: 'Tytuł'
gist.new.description: 'Opis'
gist.new.url: 'URL'
gist.new.filename-with-extension: 'Nazwa pliku z rozszerzeniem'
gist.new.indent-mode: 'Tryb wcięcia'
gist.new.indent-mode-space: 'Spacje'
gist.new.indent-mode-tab: 'Tabulatory'
gist.new.indent-size: 'Wielkość wcięcia'
gist.new.wrap-mode: 'Tryb zawijania'
gist.new.wrap-mode-no: 'Bez zawijania'
gist.new.wrap-mode-soft: 'Miękkie zawijanie'
gist.new.add-file: 'Dodaj plik'
gist.new.create-public-button: 'Stwórz publiczny Gist'
gist.new.create-unlisted-button: 'Stwórz niepubliczny Gist'
gist.new.create-private-button: 'Stwórz prywatny Gist'
gist.new.preview: 'Podgląd'
gist.new.create-a-new-gist: 'Stwórz nowy Gist'
gist.edit.editing: 'Edytowanie'
gist.edit.edit-gist: 'Edytuj %s'
gist.edit.change-visibility: 'Zmień widoczność na'
gist.edit.delete: 'Usuń'
gist.edit.cancel: 'Anuluj'
gist.edit.save: 'Zapisz'
gist.delete.confirm: 'Czy na pewno chcesz usunąć ten Gist?'
gist.list.joined: 'Dołączono'
gist.list.all: 'Wszystkie Gisty'
gist.list.search-results: 'Wyniki wyszukiwania'
gist.list.sort: 'Sortuj'
gist.list.sort-by-created: 'utworzono'
gist.list.sort-by-updated: 'zaktualizowano'
gist.list.order-by-asc: 'Najdawniej'
gist.list.order-by-desc: 'Ostatnio'
gist.list.select-tab: 'Wybierz kartę'
gist.list.liked: 'Polubiane'
gist.list.likes: 'polubień'
gist.list.forked: 'Zforkowane'
gist.list.forked-from: 'Zforkowane z'
gist.list.forks: 'forków'
gist.list.files: 'plików'
gist.list.last-active: 'Ostatnio aktywne'
gist.list.no-gists: 'Brak Gistów'
gist.list.all-liked-by: 'Wszystkie Gisty polubione przez %s'
gist.list.all-forked-by: 'Wszystkie Gisty zforkowane przez %s'
gist.list.all-from: 'Wszystkie Gisty od %s'
gist.search.found: 'Gistów znaleziono'
gist.search.no-results: 'Nie znaleziono żadnych Gistów'
gist.search.help.user: 'Gisty stworzone przez użytkownika'
gist.search.help.title: 'Gisty z podanym tytułem'
gist.search.help.filename: 'Gisty zawierające pliki z podanym tytułem'
gist.search.help.extension: 'Gisty zawierające pliki z podanym rozszerzeniem'
gist.search.help.language: 'Gisty zawierające pliki z podanym językiem'
gist.forks: 'Forki'
gist.forks.view: 'Zobacz forka'
gist.forks.no: 'Brak publicznych forków'
gist.forks.for: 'Forki dla %s'
gist.likes: 'Polubienia'
gist.likes.no: 'Brak polubień'
gist.likes.for: 'Polubienia dla %s'
gist.revisions: 'Rewizje'
gist.revision.revised: 'zrewidował ten Gist'
gist.revision.go-to-revision: 'Przejdź do rewizji'
gist.revision.file-created: 'stworzono plik'
gist.revision.file-deleted: 'usunięto plik'
gist.revision.file-renamed: 'zmieniono nazwę na'
gist.revision.diff-truncated: 'Porównanie jest za duże do pokazania'
gist.revision.file-renamed-no-changes: 'Zmieniono nazwę pliku bez modyfikacji zawartości'
gist.revision.empty-file: 'Pusty plik'
gist.revision.no-changes: 'Brak zmian'
gist.revision.no-revisions: 'Brak rewizji do pokazania'
gist.revision-of: 'Rewizja %s'
settings: 'Ustawienia'
settings.email: 'Email'
settings.email-help: 'Używany do commitów i Gravatar'
settings.email-set: 'Ustaw email'
settings.link-accounts: 'Połącz konta'
settings.link-github-account: 'Połącz konto GitHub'
settings.link-gitlab-account: 'Połącz konto GitLab'
settings.link-gitea-account: 'Połącz konto Gitea'
settings.unlink-github-account: 'Odłącz konto GitHub'
settings.unlink-gitlab-account: 'Odłącz konto GitLab'
settings.unlink-gitea-account: 'Odłącz konto Gitea'
settings.delete-account: 'Usuń konto'
settings.delete-account-confirm: 'Czy na pewno chcesz usunąć swoje konto?'
settings.add-ssh-key: 'Dodaj klucz SSH'
settings.add-ssh-key-help: 'Używany tylko do operacji pull/push za pomocą Git przez SSH'
settings.add-ssh-key-title: 'Tytuł'
settings.add-ssh-key-content: 'Klucz'
settings.delete-ssh-key: 'Usuń'
settings.delete-ssh-key-confirm: 'Potwierdź usunięcie klucza SSH'
settings.ssh-key-added-at: 'Dodany'
settings.ssh-key-never-used: 'Nigdy nie użyty'
settings.ssh-key-last-used: 'Ostatnio użyty'
settings.ssh-key-exists: 'Klucz SSH już istnieje'
settings.change-username: 'Zmień nazwę użytkownika'
settings.create-password: 'Stwórz hasło'
settings.create-password-help: 'Stwórz swoje hasło do logowania się do Opengist przez HTTP'
settings.change-password: 'Zmień hasło'
settings.change-password-help: 'Zmień swoje hasło do logowania się do Opengist przez HTTP'
settings.password-label-title: 'Hasło'
auth.signup-disabled: 'Rejestracja została wyłączona przez administratora'
auth.login: 'Zaloguj się'
auth.signup: 'Zarejestruj się'
auth.new-account: 'Nowe konto'
auth.username: 'Nazwa użytkownika'
auth.password: 'Hasło'
auth.register-instead: 'Lub zarejestruj się'
auth.login-instead: 'Lub zaloguj się'
auth.oauth: 'Kontynuuj z kontem %s'
auth.mfa: 'Weryfikacja wieloskładnikowa'
auth.mfa.passkey: 'Klucz Passkey'
auth.mfa.passkeys: 'Klucze Passkey'
auth.mfa.use-passkey: 'Użyj klucza Passkey'
auth.mfa.bind-passkey: 'Powiąż klucz Passkey'
auth.mfa.login-with-passkey: 'Zaloguj się za pomocą klucza Passkey'
auth.mfa.waiting-for-passkey-input: 'Oczekiwanie na wejście z interakcji przeglądarki...'
auth.mfa.use-passkey-to-finish: 'Użyj klucza Passkey aby dokończyć logowanie'
auth.mfa.passkeys-help: 'Dodaj klucz Passkey aby logować się nim do swojego konta i aby używać go jako weryfikacji wieloskładnikowej.'
auth.mfa.passkey-name: 'Nazwa'
auth.mfa.delete-passkey: 'Usuń'
auth.mfa.passkey-added-at: 'Dodany'
auth.mfa.passkey-never-used: 'Nigdy nie użyty'
auth.mfa.passkey-last-used: 'Ostatnio użyty'
auth.mfa.delete-passkey-confirm: 'Potwierdź usunięcie klucza Passkey'
auth.totp: 'Time based one-time password (TOTP)'
auth.totp.help: 'TOTP to metoda weryfikacji dwuskładnikowej, która używa współdzielonego sekretu do generowania hasła jednorazowego użytku.'
auth.totp.use: 'Użyj TOTP'
auth.totp.regenerate-recovery-codes: 'Wygeneruje ponownie kody odzyskiwania'
auth.totp.already-enabled: 'TOTP jest już włączone'
auth.totp.invalid-secret: 'Niepoprawny sekret TOTP'
auth.totp.invalid-code: 'Niepoprawny kod TOTP'
auth.totp.code-used: 'Kod odzyskiwania %s został użyty, jest teraz nieważny. Możesz chcieć wyłączyć weryfikację wieloskładnikową na teraz lub wygenerować swoje kody ponownie.'
auth.totp.disabled: 'TOTP zostało pomyślnie wyłączone'
auth.totp.disable: 'Wyłącz TOTP'
auth.totp.enter-code: 'Wpisz kod z aplikacji uwierzytelniajacej'
auth.totp.enter-recovery-key: 'lub kod odzyskiwania jeśli zgubiłeś swoje urządzenie'
auth.totp.code: 'Kod'
auth.totp.submit: 'Prześlij'
auth.totp.proceed: 'Dalej'
auth.totp.save-recovery-codes: 'Zapis swoje kody odzyskiwania w bezpiecznym miejscu. Możesz użyć tych kodów, aby odzyskać dostęp do swojego konta jeśli stracisz dostęp do swojej aplikacji uwierzytelniajacej.'
auth.totp.scan-qr-code: 'Zeskanuj kod QR poniżej używając swojej aplikacji uwierzytelniajacej, aby włączyć weryfikację dwuskładnikową lub wpisz następujący ciąg i potwierdź go wygenerowanym kodem.'
error: 'Błąd'
error.page-not-found: 'Nie znaleziono strony'
error.bad-request: 'Złe żądanie'
error.signup-disabled: 'Rejestracja jest wyłączona'
error.signup-disabled-form: 'Rejestracja za pomocą formularza rejestracyjnego jest wyłączona'
error.login-disabled-form: 'Logowanie za pomocą formularza logowania jest wyłączone'
error.complete-oauth-login: "Nie można ukończyć logowania: %s"
error.oauth-unsupported: 'Niewspierany dostawca'
error.cannot-bind-data: 'Nie można powiązać danych'
error.invalid-number: 'Niepoprawna liczba'
error.invalid-character-unescaped: 'Nieprawidłowy niechroniony znak'
error.not-in-mfa-session: 'Użytkownik nie jest w sesji uwierzytelnienia wieloskładnikowego'
header.menu.all: 'Wszystko'
header.menu.new: 'Nowy'
header.menu.search: 'Szukaj'
header.menu.my-gists: 'Moje Gisty'
header.menu.liked: 'Polubione'
header.menu.admin: 'Admin'
header.menu.settings: 'Ustawienia'
header.menu.logout: 'Wyloguj się'
header.menu.register: 'Zarejestruj się'
header.menu.login: 'Zaloguj się'
header.menu.light: 'Jasny'
header.menu.dark: 'Ciemny'
header.menu.system: 'Systemowy'
footer.powered-by: 'Obsługiwane przez %s'
pagination.older: 'Starsze'
pagination.newer: 'Nowsze'
pagination.previous: 'Poprzedni'
pagination.next: 'Nastepny'
admin.admin_panel: 'Panel administracyjny'
admin.general: 'Ogólne'
admin.users: 'Użytkownicy'
admin.gists: 'Gisty'
admin.configuration: 'Konfiguracja'
admin.invitations: 'Zaproszenia'
admin.invitations.create: 'Stwórz zaproszenie'
admin.versions: 'Wersje'
admin.ssh_keys: 'Klucze SSH'
admin.stats: 'Statystyki'
admin.actions: 'Akcje'
admin.actions.sync-fs: 'Synchronizuj Gisty z systemu plików'
admin.actions.sync-db: 'Synchronizuj Gisty z bazy danych'
admin.actions.git-gc: 'Zbierz śmieci we wszystkich repozytoriach Git'
admin.actions.sync-previews: 'Synchronizuj podglądy wszystkich Gistów'
admin.actions.reset-hooks: 'Zresetuj hooki serwera Git dla wszystkich repozytoriów'
admin.actions.index-gists: 'Indeksuj wszystkie Gisty'
admin.id: 'ID'
admin.user: 'Użytkownik'
admin.delete: 'Usuń'
admin.created_at: 'Utworzono'
admin.config-link: 'Ta konfiguracja może zostać %s przez plik konfiguracyjny YAML i/lub zmienne środowiskowe.'
admin.config-link-overriden: 'nadpisana'
admin.disable-signup: 'Wyłącz rejestrację'
admin.disable-signup_help: 'Zabroń tworzenia nowych kont.'
admin.require-login: 'Wymagaj logowania'
admin.require-login_help: 'Wymagaj od użytkowników zalogowania się, aby mogli zobaczyć Gisty.'
admin.allow-gists-without-login: 'Zezwól na indywidualne Gisty bez logowania'
admin.allow-gists-without-login_help: 'Zezwalaj na przeglądanie i pobieranie pojedynczych Gistów bez logowania, ale wymagaj zalogowania się w celu odkrywania Gistów.'
admin.disable-login: 'Wyłącz formularz logowania'
admin.disable-login_help: 'Zabroń logowania się za pomocą formularza logowania, aby wymusić korzystanie z dostawców OAuth.'
admin.disable-gravatar: 'Wyłącz Gravatar'
admin.disable-gravatar_help: 'Wyłącz używanie Gravatar jako dostawcy awatarów.'
admin.users.delete_confirm: 'Czy chcesz usunąć tego użytkownika?'
admin.gists.title: 'Tytuł'
admin.gists.private: 'Prywatny?'
admin.gists.nb-files: 'Liczba plików'
admin.gists.nb-likes: 'Liczba polubień'
admin.gists.delete_confirm: 'Czy chcesz usunąć tego Gista?'
admin.invitations.help: 'Zaproszenia mogą być używane, aby stworzyć konto nawet, jeśli rejestracja jest wyłączona.'
admin.invitations.max_uses: 'Maksymalna liczba użyć'
admin.invitations.expires_at: 'Wygasa'
admin.invitations.code: 'Kod'
admin.invitations.copy_link: 'Kopiuj link'
admin.invitations.uses: 'Użyć'
admin.invitations.expired: 'Wygasło'
flash.admin.user-deleted: 'Użytkownik został usunięty'
flash.admin.gist-deleted: 'Gist został usunięty'
flash.admin.invitation-created: 'Zaproszenie zostało stworzone'
flash.admin.invitation-deleted: 'Zaproszenie zostało usunięte'
flash.admin.sync-fs: 'Synchronizowanie repozytoriów z systemu plików...'
flash.admin.sync-db: 'Synchronizowanie repozytoriów z bazy danych...'
flash.admin.git-gc: 'Zbieranie śmieci w repozytoriach...'
flash.admin.sync-previews: 'Synchronizowanie podglądów Gistów...'
flash.admin.reset-hooks: 'Resetowanie hooków serwera Git dla wszystkich repozytoriów...'
flash.admin.index-gists: 'Indeksowanie wszystkich Gistów...'
flash.auth.username-exists: 'Nazwa użytkownika już istnieje'
flash.auth.invalid-credentials: 'Niepoprawne dane logowania'
flash.auth.account-linked-oauth: 'Konto połączone z %s'
flash.auth.account-unlinked-oauth: 'Konto odłączone od %s'
flash.auth.user-sshkeys-not-retrievable: 'Nie można uzyskać kluczy użytkownika'
flash.auth.user-sshkeys-not-created: 'Nie można stworzyć klucza SSH'
flash.auth.must-be-logged-in: 'Musisz być zalogowany, aby widzieć Gisty'
flash.auth.passkey-registred: 'Zarejestrowano klucz Passkey %s'
flash.auth.passkey-deleted: 'Usunięto klucz Passkey'
flash.gist.visibility-changed: 'Widoczność Gista została zmieniona'
flash.gist.deleted: 'Gist został usunięty'
flash.gist.fork-own-gist: 'Nie można forkować własnych Gistów'
flash.gist.forked: 'Gist został zforkowany'
flash.user.email-updated: 'Email został zaktualizowany'
flash.user.invalid-ssh-key: 'niepoprawny klucz SSH'
flash.user.ssh-key-added: 'Dodano klucz SSH'
flash.user.ssh-key-deleted: 'Usunięto klucz SSH'
flash.user.password-updated: 'Zaktualizowano hasło'
flash.user.username-updated: 'Zaktualizowano nazwę użytkownika'
validation.is-too-long: 'Pole %s jest za długie'
validation.should-not-be-empty: 'Pole %s nie może być puste'
validation.should-not-include-sub-directory: 'Pole %s nie może zawierać podfolderu'
validation.should-only-contain-alphanumeric-characters: 'Pole %s może tylko zawierać znaki alfanumeryczne'
validation.should-only-contain-alphanumeric-characters-and-dashes: 'Pole %s może tylko zawierać znaki alfanumeryczne i myślniki'
validation.not-enough: 'Nie wystarczająco %s'
validation.invalid: 'Niepoprawny %s'
html.title.admin-panel: 'Panel administracyjny'
admin.invitations.delete_confirm: Czy chcesz usunąć to zaproszenie?

View File

@@ -1,6 +1,6 @@
gist.public: 公开
gist.unlisted: 非列出
gist.private:
gist.private:
gist.header.like: 喜欢
gist.header.unlike: 取消喜欢
@@ -14,11 +14,11 @@ gist.header.code: 代码
gist.header.revisions: 修订
gist.header.revision: 修订
gist.header.clone-http: 通过 %s 克隆
gist.header.clone-http-help: 使用 Git 通过 HTTP 基础认证克隆。
gist.header.clone-http-help: 使用 HTTP 基础认证通过 Git 克隆。
gist.header.clone-ssh: 通过 SSH 克隆
gist.header.clone-ssh-help: 使用 Git 通过 SSH 密钥克隆。
gist.header.clone-ssh-help: 使用 SSH 密钥通过 Git 克隆。
gist.header.embed: '嵌入'
gist.header.embed-help: '在你的网页中嵌入此gist。'
gist.header.embed-help: '将此 Gist 嵌入到您的网站。'
gist.header.download-zip: 下载 ZIP
gist.raw: 原始文件
@@ -27,10 +27,10 @@ gist.watch-full-file: 查看完整文件。
gist.file-not-valid: 此文件不是有效的 CSV 文件。
gist.no-content: 没有内容
gist.new.new_gist: 建 Gist
gist.new.new_gist: 建 Gist
gist.new.title: 标题
gist.new.description: 描述
gist.new.filename-with-extension: 文件名与扩展
gist.new.filename-with-extension: 带扩展名的文件名
gist.new.indent-mode: 缩进模式
gist.new.indent-mode-space: 空格
gist.new.indent-mode-tab: 制表符
@@ -39,17 +39,17 @@ gist.new.wrap-mode: 换行模式
gist.new.wrap-mode-no: 不自动换行
gist.new.wrap-mode-soft: 软换行
gist.new.add-file: 添加文件
gist.new.create-public-button: 创建公开 Gist
gist.new.create-unlisted-button: 创建非列出 Gist
gist.new.create-private-button: 创建私 Gist
gist.new.create-public-button: 创建公开 Gist
gist.new.create-unlisted-button: 创建非列出 Gist
gist.new.create-private-button: 创建私密的 Gist
gist.edit.editing: 编辑
gist.edit.editing: 正在编辑
gist.edit.change-visibility: 设为
gist.edit.delete: 删除
gist.edit.cancel: 取消
gist.edit.save: 保存
gist.list.joined: 加入
gist.list.joined: 加入
gist.list.all: 所有 Gists
gist.list.search-results: 搜索结果
gist.list.sort: 排序
@@ -65,30 +65,30 @@ gist.list.forked-from: 派生自
gist.list.forks: 派生
gist.list.files: 文件
gist.list.last-active: 最后活跃于
gist.list.no-gists: 没有 Gist
gist.list.no-gists: 没有任何 Gist
gist.forks: 派生
gist.forks.view: 查看派生
gist.forks.no: 公开派生
gist.forks.no: 没有任何公开派生
gist.likes: 喜欢
gist.likes.no: 还没有喜欢
gist.likes.no: 目前还没有任何喜欢
gist.revisions: 修订
gist.revision.revised: 修订了这个 Gist
gist.revision.go-to-revision: 跳至此修订
gist.revision.go-to-revision: 转到此修订
gist.revision.file-created: 文件已创建
gist.revision.file-deleted: 文件已删除
gist.revision.file-deleted: 文件已删除
gist.revision.file-renamed: 重命名为
gist.revision.diff-truncated: 由于变更差异过大,显示内容已被截断
gist.revision.file-renamed-no-changes: 文件已重命名,但名称与之前没有差异
gist.revision.empty-file: 文件
gist.revision.no-changes: 没有变更
gist.revision.diff-truncated: 差异内容过多而无法显示
gist.revision.file-renamed-no-changes: 文件已重命名,但内容与之前没有差异
gist.revision.empty-file: 文件为空
gist.revision.no-changes: 没有任何变更
gist.revision.no-revisions: 无可供显示的修订
settings: 设置
settings.email: 邮箱
settings.email-help: 用于提交 Gravatar
settings.email: 电子邮箱
settings.email-help: 用于提交 Gravatar 头像
settings.email-set: 设置邮箱地址
settings.link-accounts: 关联账号
settings.link-github-account: 关联 GitHub 账号
@@ -98,16 +98,16 @@ settings.unlink-gitea-account: 解除关联 Gitea 账号
settings.delete-account: 删除账号
settings.delete-account-confirm: 您确认要删除您的账号吗?
settings.add-ssh-key: 添加 SSH 密钥
settings.add-ssh-key-help: 用于使用 Git 通过 SSH 拉取与推送 Gist
settings.add-ssh-key-title: 标题
settings.add-ssh-key-help: 用于使用 Git 通过 SSH 拉取与推送 Gist
settings.add-ssh-key-title: 名称
settings.add-ssh-key-content: 密钥
settings.delete-ssh-key: 删除
settings.delete-ssh-key-confirm: 确认删除 SSH 密钥
settings.ssh-key-added-at: 添加
settings.ssh-key-added-at: 添加
settings.ssh-key-never-used: 从未使用过
settings.ssh-key-last-used: 最后使用于
auth.signup-disabled: 管理员已禁用注册
auth.signup-disabled: 管理员已禁用注册
auth.login: 登录
auth.signup: 注册
auth.new-account: 新建账号
@@ -120,7 +120,7 @@ auth.oauth: 使用 %s 账号继续
error: 错误
header.menu.all: 全部
header.menu.new:
header.menu.new:
header.menu.search: 搜索
header.menu.my-gists: 我的 Gists
header.menu.liked: 喜欢的 Gists
@@ -129,13 +129,13 @@ header.menu.settings: 设置
header.menu.logout: 登出
header.menu.register: 注册
header.menu.login: 登录
header.menu.light: 亮色
header.menu.dark: 暗色
header.menu.system: 系统
header.menu.light: 亮色模式
header.menu.dark: 暗色模式
header.menu.system: 跟随系统
footer.powered-by: 由 %s 强力驱动
pagination.older: 更早
pagination.newer: 更新
pagination.older: 下一页
pagination.newer: 上一页
pagination.previous: 上一页
pagination.next: 下一页
@@ -156,92 +156,92 @@ admin.user: 用户
admin.delete: 删除
admin.created_at: 创建于
admin.config-link: 此配置可通过 YAML 配置和/或环境变量进行 %s 。
admin.config-link: 此配置可通过 YAML 配置文件和/或环境变量进行 %s 。
admin.config-link-overriden: 覆盖
admin.disable-signup: 注册
admin.disable-signup_help: 止创建新的账号。
admin.require-login: 要求登录
admin.disable-signup: 止用户注册
admin.disable-signup_help: 止创建新的账号。
admin.require-login: 登录访问限制
admin.require-login_help: 强制用户登录后才能查看 Gist。
admin.disable-login: 禁用登录表单
admin.disable-login_help: 禁止使用登录表单进行登录以强制通过 OAuth 提供方登录。
admin.disable-gravatar: 禁用 Gravatar
admin.disable-gravatar_help: 停止使用 Gravatar 作为头像提供方。
admin.allow-gists-without-login: 允许未登录状态下输入个人 gists
admin.allow-gists-without-login_help: 允许在不登录的情况下查看和下载 gist同时需要登录才能使用 gists 的发现功能。
admin.users.delete_confirm: 想要删除此用户吗?
admin.allow-gists-without-login: 允许未登录状态下访问单个 Gists
admin.allow-gists-without-login_help: 允许在不登录的情况下查看和下载 Gist同时需要登录才能使用 Gists 的发现功能。
admin.users.delete_confirm: 想要删除此用户吗?
admin.gists.title: 标题
admin.gists.private: 私有?
admin.gists.private: 访问权限
admin.gists.nb-files: 文件数
admin.gists.nb-likes: 喜欢数
admin.gists.delete_confirm: 想要删除此 Gist 吗?
gist.new.url: 'URL'
gist.new.preview: '预览 gist'
admin.gists.delete_confirm: 想要删除此 Gist 吗?
gist.new.url: '自定义 URL 路径名'
gist.new.preview: '预览'
error.page-not-found: '页面未找到'
gist.new.create-a-new-gist: '创建一个新的gist'
gist.new.create-a-new-gist: '创建一个新的 Gist'
gist.edit.edit-gist: '编辑 %s'
gist.list.all-liked-by: '所有 gists 被 %s 标记喜欢'
gist.list.all-forked-by: '所有 gists 被 %s 派生'
gist.list.all-from: '所有 gists 来自于 %s'
gist.search.found: '以下是找到的 gists'
gist.search.no-results: '没有找到gist'
gist.search.help.user: '由用户创建的gist'
gist.search.help.title: '包含指定标题的 gists'
gist.search.help.filename: 'gists 文件中包含指定名称'
gist.search.help.extension: 'gists 文件中包含指定插件'
gist.search.help.language: 'gists 文件中包含指定的开发语言'
gist.forks.for: '派生到 %s'
gist.likes.for: '喜欢给 %s'
gist.revision-of: '%s 修订'
gist.list.all-liked-by: '%s 喜欢的所有 Gists'
gist.list.all-forked-by: '%s 派生的所有 Gists'
gist.list.all-from: '来自于 %s 的所有 Gists'
gist.search.found: '个已找到的 Gist(s)'
gist.search.no-results: '没有找到任何 Gist'
gist.search.help.user: '由用户创建的 Gists'
gist.search.help.title: '包含指定标题的 Gists'
gist.search.help.filename: '包含指定文件名的 Gists'
gist.search.help.extension: '包含指定扩展名的 Gists'
gist.search.help.language: '包含指定编程语言的 Gists'
gist.forks.for: '%s 的派生'
gist.likes.for: '%s 的喜欢'
gist.revision-of: '%s 修订'
settings.link-gitlab-account: '关联 GitLab 账号'
settings.unlink-gitlab-account: '解除关联 GitLab 账号'
settings.change-username: '修改用户名'
settings.create-password: '创建密码'
settings.create-password-help: '创建密码用于 HTTP 方式登录 Opengist'
settings.create-password-help: '创建您的密码以通过 HTTP 方式登录 Opengist'
settings.change-password: '修改密码'
settings.change-password-help: '修改您的密码用于 HTTP 方式登录 Opengist'
settings.change-password-help: '修改您通过 HTTP 登录 Opengist 的密码'
settings.password-label-title: '密码'
error.bad-request: '请求错误'
error.signup-disabled: '注册功能已被管理员禁用'
error.signup-disabled-form: '已禁用了表单注册功能'
error.login-disabled-form: '已禁用了表单登录功能'
error.complete-oauth-login: '用户认证未能通过: %s'
error.signup-disabled: '注册已被禁用'
error.signup-disabled-form: '通过用户名密码注册已被禁用'
error.login-disabled-form: '通过用户名密码登录已被禁用'
error.complete-oauth-login: '用户认证未能通过%s'
error.oauth-unsupported: '不支持的认证提供商'
error.cannot-bind-data: '无法绑定数据'
error.invalid-number: '数字格式不正确'
error.invalid-character-unescaped: '包含未转义的无效字符'
admin.invitations: '邀请'
admin.invitations.create: '创建邀请'
admin.actions.sync-previews: '同步所有 gists 预览'
admin.actions.reset-hooks: '重置所有存储库的 Git 服务hooks'
admin.actions.index-gists: '索引所有 gists'
admin.actions.sync-previews: '同步所有 Gists 预览'
admin.actions.reset-hooks: '重置所有存储库的 Git 服务 hooks'
admin.actions.index-gists: '索引所有 Gists'
admin.invitations.help: '即使在禁用注册功能的情况下,邀请功能也可用于创建帐户。'
admin.invitations.max_uses: '最多使用次数'
admin.invitations.expires_at: '过期时间'
admin.invitations.code: '邀请码'
admin.invitations.copy_link: '复制链接'
admin.invitations.uses: '使用次数'
admin.invitations.expired: '已期'
flash.admin.user-deleted: '用户已删除'
flash.admin.gist-deleted: 'Gist 已删除'
flash.admin.invitation-created: '邀请已被创建'
flash.admin.invitation-deleted: '邀请已被删除'
admin.invitations.expired: '已期'
flash.admin.user-deleted: '用户已删除'
flash.admin.gist-deleted: 'Gist 已删除'
flash.admin.invitation-created: '邀请已被创建'
flash.admin.invitation-deleted: '邀请已被删除'
flash.admin.sync-fs: '正在从文件系统同步存储库...'
flash.admin.sync-db: '正在从数据库同步存储库...'
flash.admin.git-gc: '正在进行存储库垃圾回收...'
flash.admin.sync-previews: '正在同步 Gist 预览...'
flash.admin.reset-hooks: '正在重置所有存储库的 Git 服务挂钩...'
flash.admin.index-gists: '索引所有 gists...'
flash.admin.index-gists: '正在索引所有 Gists...'
flash.auth.username-exists: '用户名已存在'
flash.auth.invalid-credentials: '无效的凭证'
flash.auth.account-linked-oauth: '帐户已关联到 %s'
flash.auth.account-unlinked-oauth: '帐户与 %s 解除关联'
flash.auth.user-sshkeys-not-retrievable: '无法获取用户密钥'
flash.auth.user-sshkeys-not-created: '无法创建 ssh 密钥'
flash.auth.must-be-logged-in: '您必须登录才能访问 gists'
flash.gist.visibility-changed: 'Gist可见性已更改'
flash.gist.deleted: 'Gist已被删除'
flash.gist.fork-own-gist: '无法派生自己的要点'
flash.auth.user-sshkeys-not-created: '无法创建 SSH 密钥'
flash.auth.must-be-logged-in: '您必须登录才能访问 Gists'
flash.gist.visibility-changed: 'Gist 可见性已更改'
flash.gist.deleted: 'Gist 已被删除'
flash.gist.fork-own-gist: '无法派生自己的 Gists'
flash.gist.forked: 'Gist 已被派生'
flash.user.email-updated: '电子邮件已更新'
flash.user.invalid-ssh-key: 'SSH 密钥无效'
@@ -254,20 +254,20 @@ validation.should-not-be-empty: '字段 %s 不能为空'
validation.should-not-include-sub-directory: '字段 %s 不应包含子目录'
validation.should-only-contain-alphanumeric-characters: '字段 %s 只能包含字母、数字、字符'
validation.should-only-contain-alphanumeric-characters-and-dashes: '字段 %s 应仅包含字母、数字、字符和 -'
validation.not-enough: '还不够 %s'
validation.invalid: '无效 %s'
validation.not-enough: '%s 长度过短'
validation.invalid: '%s 无效'
html.title.admin-panel: '管理面板'
settings.ssh-key-exists: SSH 密钥已经存在
auth.mfa.passkey-name: 密钥名称
auth.mfa.use-passkey-to-finish: 使用密钥完成身份验证
auth.mfa.delete-passkey: 删除密钥
auth.mfa.passkey-name: 名称
auth.mfa.use-passkey-to-finish: 使用通行密钥完成身份验证
auth.mfa.delete-passkey: 删除
auth.mfa.passkey-added-at: 密钥已添加
auth.mfa.passkey-never-used: 密钥从未使用
auth.mfa.passkey-last-used: 密钥上次使用时间
auth.mfa.passkey-never-used: 从未使用
auth.mfa.passkey-last-used: 最后使用于
auth.mfa.delete-passkey-confirm: 确认删除密钥
error.not-in-mfa-session: 用户不在 MFA 会话中
auth.mfa.waiting-for-passkey-input: 等待浏览器的交互输入...
auth.mfa.passkeys-help: 添加密钥以登录您的帐户并用 MFA 方
auth.mfa.passkeys-help: 添加通行密钥以登录您的帐户并用 MFA 方
flash.auth.passkey-registred: 密钥 %s 已注册
flash.auth.passkey-deleted: 密钥已删除
auth.mfa.use-passkey: 使用通行密钥
@@ -276,3 +276,22 @@ auth.mfa.login-with-passkey: 使用通行密钥登录
auth.mfa: 多因素认证
auth.mfa.passkey: 通行密钥
auth.mfa.passkeys: 通行密钥
gist.delete.confirm: 确定要删除此 Gist 吗?
auth.totp.scan-qr-code: 使用您的身份验证应用扫描下面的二维码以启用双因素认证,或者输入以下字符串,然后用生成的代码进行确认。
auth.totp: 基于时间的一次性密码算法TOTP
auth.totp.help: TOTP 是一种双因素认证方法,它使用共享密钥生成一次性密码。
auth.totp.use: 使用 TOTP
auth.totp.regenerate-recovery-codes: 重新生成恢复码
auth.totp.already-enabled: TOTP 已启用
auth.totp.invalid-secret: 无效的 TOTP 密钥
auth.totp.code-used: 恢复代码 %s 已被使用且失效。您可能需要暂时禁用 MFA 或重新生成代码。
auth.totp.invalid-code: 无效的 TOTP 代码
auth.totp.disabled: 成功禁用 TOTP
auth.totp.disable: 禁用 TOTP
auth.totp.enter-code: 请输入来自身份验证器应用程序的代码
auth.totp.enter-recovery-key: 如果您丢失了设备,可以使用恢复密钥
auth.totp.code: 代码
auth.totp.submit: 提交
auth.totp.proceed: 继续
auth.totp.save-recovery-codes: 请将您的恢复代码保存在安全的地方。在您无法访问身份验证应用程序时,可以使用这些代码恢复访问。
admin.invitations.delete_confirm: 您想要删除此邀请吗?

View File

@@ -41,6 +41,7 @@ func runGitCommand(ch ssh.Channel, gitCmd string, key string, ip string) error {
allowUnauthenticated, err := auth.ShouldAllowUnauthenticatedGistAccess(db.AuthInfo{}, true)
if err != nil {
errorSsh("Failed to get auth info", err)
return errors.New("internal server error")
}

View File

@@ -4,6 +4,7 @@ import (
"archive/zip"
"bufio"
"bytes"
gojson "encoding/json"
"errors"
"fmt"
"html/template"
@@ -428,12 +429,10 @@ func gistJs(ctx echo.Context) error {
return errorRes(500, "Error joining css url", err)
}
js := `document.write('<link rel="stylesheet" href="%s">')
document.write('%s')
`
content := strings.Replace(htmlbuf.String(), `\n`, `\\n`, -1)
content = strings.Replace(content, "\n", `\n`, -1)
js = fmt.Sprintf(js, cssUrl, content)
js, err := escapeJavaScriptContent(htmlbuf.String(), cssUrl)
if err != nil {
return errorRes(500, "Error escaping JavaScript content", err)
}
ctx.Response().Header().Set("Content-Type", "application/javascript")
return plainText(ctx, 200, js)
}
@@ -894,3 +893,25 @@ func preview(ctx echo.Context) error {
return plainText(ctx, 200, previewStr)
}
func escapeJavaScriptContent(htmlContent, cssUrl string) (string, error) {
jsonContent, err := gojson.Marshal(htmlContent)
if err != nil {
return "", fmt.Errorf("failed to encode content: %w", err)
}
jsonCssUrl, err := gojson.Marshal(cssUrl)
if err != nil {
return "", fmt.Errorf("failed to encode CSS URL: %w", err)
}
js := fmt.Sprintf(`
document.write('<link rel="stylesheet" href=%s>');
document.write(%s);
`,
string(jsonCssUrl),
string(jsonContent),
)
return js, nil
}

View File

@@ -164,7 +164,7 @@ type Server struct {
dev bool
}
func NewServer(isDev bool, sessionsPath string) *Server {
func NewServer(isDev bool, sessionsPath string, ignoreCsrf bool) *Server {
dev = isDev
flashStore = sessions.NewCookieStore([]byte("opengist"))
encryptKey, _ := utils.GenerateSecretKey(filepath.Join(sessionsPath, "session-encrypt.key"))
@@ -245,15 +245,16 @@ func NewServer(isDev bool, sessionsPath string) *Server {
// Web based routes
g1 := e.Group("")
{
if !dev {
if !ignoreCsrf {
g1.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{
TokenLookup: "form:_csrf,header:X-CSRF-Token",
CookiePath: "/",
CookieHTTPOnly: true,
CookieSameSite: http.SameSiteStrictMode,
}))
g1.Use(csrfInit)
}
g1.Use(csrfInit)
g1.GET("/", create, logged)
g1.POST("/", processCreate, logged)
g1.POST("/preview", preview, logged)

View File

@@ -33,7 +33,7 @@ type testServer struct {
func newTestServer() (*testServer, error) {
s := &testServer{
server: web.NewServer(true, path.Join(config.GetHomeDir(), "tmp", "sessions")),
server: web.NewServer(true, path.Join(config.GetHomeDir(), "tmp", "sessions"), true),
}
go s.start()

3119
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -73,10 +73,14 @@ document.addEventListener("DOMContentLoaded", () => {
} else {
const formData = new FormData();
formData.append('content', editor.state.doc.toString());
let csrf = document.querySelector<HTMLInputElement>('form#create input[name="_csrf"]').value
fetch(`${baseUrl}/preview`, {
method: 'POST',
credentials: 'same-origin',
body: formData
body: formData,
headers: {
'X-CSRF-Token': csrf
}
}).then(r => r.text()).then(r => {
let divpreview = dom.querySelector("div.preview") as HTMLElement;
divpreview!.innerHTML = r;

View File

@@ -46,9 +46,9 @@
{{ end }}
{{ if .htmlTitle }}
<title>{{ .htmlTitle }} - Opengist</title>
<title>{{ .htmlTitle }} - {{ if $.c.CustomName }}{{ $.c.CustomName }}{{ else }}Opengist{{ end }}</title>
{{ else }}
<title>Opengist</title>
<title>{{ if $.c.CustomName }}{{ $.c.CustomName }}{{ else }}Opengist{{ end }}</title>
{{ end }}
</head>
<body class="h-full">

View File

@@ -75,9 +75,9 @@
{{ .locale.Tr "gist.header.edit" }}
</a>
</div>
<form id="delete" onsubmit="return confirm('Are you sure you want to delete this gist ?')" class="ml-2 flex items-center" method="post" action="{{ $.c.ExternalUrl }}/{{ .gist.User.Username }}/{{ .gist.Identifier }}/delete">
<form id="delete" class="ml-2 flex items-center" method="post" action="{{ $.c.ExternalUrl }}/{{ .gist.User.Username }}/{{ .gist.Identifier }}/delete">
{{ .csrfHtml }}
<button type="submit" class="relative inline-flex items-center space-x-2 rounded-md border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 px-2 py-1.5 text-xs font-medium text-rose-600 dark:text-rose-400 hover:bg-rose-500 hover:text-white dark:hover:bg-rose-600 hover:border-rose-600 dark:hover:border-rose-700 dark:hover:text-white focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500">
<button type="submit" onclick="return confirm('{{ .locale.Tr "gist.delete.confirm" }}')" class="relative inline-flex items-center space-x-2 rounded-md border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 px-2 py-1.5 text-xs font-medium text-rose-600 dark:text-rose-400 hover:bg-rose-500 hover:text-white dark:hover:bg-rose-600 hover:border-rose-600 dark:hover:border-rose-700 dark:hover:text-white focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>

View File

@@ -28,9 +28,9 @@
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-700 dark:text-slate-300">{{ $gist.NbLikes }}</td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-700 dark:text-slate-300"><span class="moment-timestamp-date">{{ $gist.CreatedAt }}</span></td>
<td class="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
<form action="{{ $.c.ExternalUrl }}/admin-panel/gists/{{ $gist.ID }}/delete" method="POST" onsubmit="return confirm('{{ $.locale.Tr "admin.gists.delete_confirm" }}')">
<form action="{{ $.c.ExternalUrl }}/admin-panel/gists/{{ $gist.ID }}/delete" method="POST">
{{ $.csrfHtml }}
<button type="submit" class="text-rose-500 hover:text-rose-600">{{ $.locale.Tr "admin.delete" }}</button>
<button type="submit" onclick="return confirm('{{ $.locale.Tr "admin.gists.delete_confirm" }}')" class="text-rose-500 hover:text-rose-600">{{ $.locale.Tr "admin.delete" }}</button>
</form>
</td>
</tr>

View File

@@ -53,9 +53,9 @@
<td class="whitespace-nowrap py-2 px-2 text-sm">{{ $invitation.NbUsed }}/{{ $invitation.NbMax }}</td>
<td class="whitespace-nowrap px-2 py-2 text-sm"><span class="moment-timestamp-date">{{ $invitation.ExpiresAt }}</span></td>
<td class="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
<form action="{{ $.c.ExternalUrl }}/admin-panel/invitations/{{ $invitation.ID }}/delete" method="POST" onsubmit="return confirm('{{ $.locale.Tr "admin.users.delete_confirm" }}')">
<form action="{{ $.c.ExternalUrl }}/admin-panel/invitations/{{ $invitation.ID }}/delete" method="POST">
{{ $.csrfHtml }}
<button type="submit" class="text-rose-500 hover:text-rose-600">{{ $.locale.Tr "admin.delete" }}</button>
<button type="submit" onclick="return confirm('{{ $.locale.Tr "admin.invitations.delete_confirm" }}')" class="text-rose-500 hover:text-rose-600">{{ $.locale.Tr "admin.delete" }}</button>
</form>
</td>
</tr>

View File

@@ -20,9 +20,9 @@
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-700 dark:text-slate-300"><a href="{{ $.c.ExternalUrl }}/{{ $user.Username }}">{{ $user.Username }}</a></td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-700 dark:text-slate-300"><span class="moment-timestamp-date">{{ $user.CreatedAt }}</span></td>
<td class="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
<form action="{{ $.c.ExternalUrl }}/admin-panel/users/{{ $user.ID }}/delete" method="POST" onsubmit="return confirm('{{ $.locale.Tr "admin.users.delete_confirm" }}')">
<form action="{{ $.c.ExternalUrl }}/admin-panel/users/{{ $user.ID }}/delete" method="POST">
{{ $.csrfHtml }}
<button type="submit" class="text-rose-500 hover:text-rose-600">{{ $.locale.Tr "admin.delete" }}</button>
<button type="submit" class="text-rose-500 hover:text-rose-600" onclick="return confirm('{{ $.locale.Tr "admin.users.delete_confirm" }}')">{{ $.locale.Tr "admin.delete" }}</button>
</form>
</td>
</tr>

View File

@@ -87,7 +87,7 @@
</div>
</div>
</div>
{{ if .isLoginPage }}
{{ if and (.isLoginPage) (not .disableForm) }}
<div class="">
<div class="mt-8 sm:w-full sm:max-w-md">
<div class="bg-white dark:bg-gray-900 rounded-md border border-1 border-gray-200 dark:border-gray-700 py-8 px-4 shadow sm:rounded-lg sm:px-10 ">

View File

@@ -31,7 +31,7 @@
<div class="rounded-md border border-1 border-gray-200 dark:border-gray-700 editor">
<div class="border-b-1 border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 my-auto flex">
<p class="mx-2 my-2 inline-flex">
<input type="text" name="name" placeholder="{{ .locale.Tr "gist.new.filename-with-extension" }}" style="line-height: 0.05em" class="form-filename bg-white dark:bg-gray-900 shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-200 dark:border-gray-700 rounded-md gist-title">
<input type="text" name="name" placeholder="{{ .locale.Tr "gist.new.filename-with-extension" }}" style="line-height: 0.05em" class="form-filename bg-white dark:bg-gray-900 shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-200 dark:border-gray-700 rounded-md gist-title" autocomplete="off" data-lpignore data-bwignore data-1p-ignore>
<button style="line-height: 0.05em" class="hidden delete-file -ml-px relative inline-flex items-center space-x-2 px-4 py-2 border border-gray-200 dark:border-gray-700 text-sm font-medium rounded-r-md text-slate-700 dark:text-slate-300 bg-gray-50 dark:bg-gray-800 hover:bg-white dark:hover:bg-gray-900 focus:outline-none" type="button">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />

View File

@@ -28,9 +28,9 @@
</div>
</div>
</form>
<form id="delete" onsubmit="return confirm('Are you sure you want to delete this gist ?')" class="ml-2 flex items-center" method="post" action="{{ $.c.ExternalUrl }}/{{ .gist.User.Username }}/{{ .gist.Identifier }}/delete">
<form id="delete" class="ml-2 flex items-center" method="post" action="{{ $.c.ExternalUrl }}/{{ .gist.User.Username }}/{{ .gist.Identifier }}/delete">
{{ .csrfHtml }}
<button type="submit" class="relative inline-flex items-center space-x-2 rounded-md border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 px-2 py-1.5 text-xs font-medium text-rose-600 dark:text-rose-400 hover:bg-rose-500 hover:text-white dark:hover:bg-rose-600 hover:border-rose-600 dark:hover:border-rose-700 dark:hover:text-white focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500">
<button type="submit" onclick="return confirm('{{ .locale.Tr "gist.delete.confirm" }}')" class="relative inline-flex items-center space-x-2 rounded-md border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 px-2 py-1.5 text-xs font-medium text-rose-600 dark:text-rose-400 hover:bg-rose-500 hover:text-white dark:hover:bg-rose-600 hover:border-rose-600 dark:hover:border-rose-700 dark:hover:text-white focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
@@ -65,7 +65,7 @@
<div class="rounded-md border border-1 border-gray-200 dark:border-gray-700 editor">
<div class="border-b-1 border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 my-auto flex">
<p class="mx-2 my-2 inline-flex">
<input type="text" value="{{ $file.Filename }}" name="name" placeholder="{{ $.locale.Tr "gist.new.filename-with-extension" }}" style="line-height: 0.05em; z-index: 99999" class="form-filename bg-white dark:bg-gray-900 shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-200 dark:border-gray-700 {{ if eq (len $.files) 1 }}rounded-md{{ else }}rounded-l-md{{ end }} gist-title">
<input type="text" value="{{ $file.Filename }}" name="name" placeholder="{{ $.locale.Tr "gist.new.filename-with-extension" }}" style="line-height: 0.05em; z-index: 99999" class="form-filename bg-white dark:bg-gray-900 shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-200 dark:border-gray-700 {{ if eq (len $.files) 1 }}rounded-md{{ else }}rounded-l-md{{ end }} gist-title" autocomplete="off" data-lpignore data-bwignore data-1p-ignore>
<button style="line-height: 0.05em" class="{{ if eq (len $.files) 1 }}hidden{{ end }} delete-file -ml-px relative inline-flex items-center space-x-2 px-4 py-2 border border-gray-200 dark:border-gray-700 text-sm font-medium rounded-r-md text-slate-700 dark:text-slate-300 bg-gray-50 dark:bg-gray-800 hover:bg-white dark:hover:bg-gray-900 focus:outline-none" type="button">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />

View File

@@ -38,7 +38,7 @@
</div>
{{ if $file.Truncated }}
<div class="text-sm px-4 py-1.5 border-t-1 border-gray-200 dark:border-gray-700">
{{ $.locale.Tr "gist.file-truncated" }} <a href="{{ $.c.ExternalUrl }}/{{ $.gist.User.Username }}/{{ $.gist.Identifier }}/raw/{{ $.commit }}/{{$file.Filename}}">{{ $.locale.Tr "gist.watch-full-file" }}.</a>
{{ $.locale.Tr "gist.file-truncated" }} <a href="{{ $.c.ExternalUrl }}/{{ $.gist.User.Username }}/{{ $.gist.Identifier }}/raw/{{ $.commit }}/{{$file.Filename}}">{{ $.locale.Tr "gist.watch-full-file" }}</a>
</div>
{{ end }}
{{ if and (not $csv) (isCsv $file.Filename) }}

View File

@@ -8,7 +8,7 @@
</div>
{{ if $file.Truncated }}
<div class="text-xs px-4 bg-gray-50 py-1.5 border-b-1 border-gray-100 dark:border-gray-700">
{{ $.locale.Tr "gist.file-truncated" }} <a target="_blank" class="text-primary-600" href="{{ $.baseHttpUrl }}/{{ $.gist.User.Username }}/{{ $.gist.Identifier }}/raw/HEAD/{{$file.Filename}}">{{ $.locale.Tr "gist.watch-full-file" }}.</a>
{{ $.locale.Tr "gist.file-truncated" }} <a target="_blank" class="text-primary-600" href="{{ $.baseHttpUrl }}/{{ $.gist.User.Username }}/{{ $.gist.Identifier }}/raw/HEAD/{{$file.Filename}}">{{ $.locale.Tr "gist.watch-full-file" }}</a>
</div>
{{ end }}
{{ $csv := csvFile $file.File }}

View File

@@ -218,10 +218,10 @@
<p class="text-xs text-gray-500 line-clamp-2">{{ $.locale.Tr "auth.mfa.passkey-last-used" }} <span class="moment-timestamp">{{ .LastUsedAt }}</span></p>
{{ end }}
</div>
<form action="{{ $.c.ExternalUrl }}/settings/passkeys/{{.ID}}" method="post" class="inline-block" onsubmit="return confirm('{{ $.locale.Tr "auth.mfa.delete-passkey-confirm" }}');">
<form action="{{ $.c.ExternalUrl }}/settings/passkeys/{{.ID}}" method="post" class="inline-block">
<input type="hidden" name="_method" value="DELETE">
{{ $.csrfHtml }}
<button type="submit" class="align-middle items-center leading-2 ml-2 px-3 py-1 border border-transparent border-gray-200 dark:border-gray-700 text-xs font-medium rounded-md shadow-sm text-white dark:text-white bg-rose-600 hover:bg-rose-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-rose-500">{{ $.locale.Tr "auth.mfa.delete-passkey" }}</button>
<button type="submit" onclick="return confirm('{{ $.locale.Tr "auth.mfa.delete-passkey-confirm" }}');" class="align-middle items-center leading-2 ml-2 px-3 py-1 border border-transparent border-gray-200 dark:border-gray-700 text-xs font-medium rounded-md shadow-sm text-white dark:text-white bg-rose-600 hover:bg-rose-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-rose-500">{{ $.locale.Tr "auth.mfa.delete-passkey" }}</button>
</form>
</div>
</li>
@@ -280,11 +280,11 @@
<p class="text-xs text-gray-500 line-clamp-2">{{ $.locale.Tr "settings.ssh-key-last-used" }} <span class="moment-timestamp">{{ .LastUsedAt }}</span></p>
{{ end }}
</div>
<form action="{{ $.c.ExternalUrl }}/settings/ssh-keys/{{.ID}}" method="post" class="inline-block" onsubmit="return confirm('{{ $.locale.Tr "settings.delete-ssh-key-confirm" }}')">
<form action="{{ $.c.ExternalUrl }}/settings/ssh-keys/{{.ID}}" method="post" class="inline-block">
<input type="hidden" name="_method" value="DELETE">
{{ $.csrfHtml }}
<button type="submit" class="align-middle items-center leading-2 ml-2 px-3 py-1 border border-transparent border-gray-200 dark:border-gray-700 text-xs font-medium rounded-md shadow-sm text-white dark:text-white bg-rose-600 hover:bg-rose-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-rose-500">{{ $.locale.Tr "settings.delete-ssh-key" }}</button>
<button type="submit" onclick="return confirm('{{ $.locale.Tr "settings.delete-ssh-key-confirm" }}')" class="align-middle items-center leading-2 ml-2 px-3 py-1 border border-transparent border-gray-200 dark:border-gray-700 text-xs font-medium rounded-md shadow-sm text-white dark:text-white bg-rose-600 hover:bg-rose-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-rose-500">{{ $.locale.Tr "settings.delete-ssh-key" }}</button>
</form>
</div>
</li>