update to v2025
@ -1,16 +0,0 @@
|
||||
# configurations
|
||||
.idea
|
||||
|
||||
# crawlee and apify storage folders
|
||||
apify_storage
|
||||
crawlee_storage
|
||||
storage
|
||||
|
||||
# pocketbase
|
||||
pocketbase
|
||||
pb_data
|
||||
|
||||
# installed files
|
||||
node_modules
|
||||
|
||||
proofs/
|
18
.editorconfig
Normal file
@ -0,0 +1,18 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
charset = utf-8
|
||||
max_line_length = 100
|
||||
semi = false
|
||||
quote_type = single
|
||||
|
||||
[*.{json,yaml,yml,toml,jsonc}]
|
||||
quote_type = double
|
||||
|
||||
[*.{html,htm}]
|
||||
max_line_length = 140
|
8
.env.example
Normal file
@ -0,0 +1,8 @@
|
||||
DONATION_XMR_ADDRESS="FAKE_VALUE"
|
||||
DONATION_XMR_ADDRESS="FAKE_VALUE"
|
||||
|
||||
WEB_DOMAIN="kycnot.me"
|
||||
ONION_ADDRESS="http://kycnotmezdiftahfmc34pqbpicxlnx3jbf5p7jypge7gdvduu7i6qjqd.onion"
|
||||
|
||||
OPENAI_API_KEY="sk-xxxxxxxxxxx"
|
||||
SECRET_TOKEN="axxxxxxxxxxxxxxxxxxxxxx" # openssl rand -hex 32
|
1
.gitattributes
vendored
@ -1 +0,0 @@
|
||||
*.css linguist-detectable=false
|
29
.gitignore
vendored
@ -1,12 +1,21 @@
|
||||
dev.sh
|
||||
blog.yml
|
||||
node_modules
|
||||
*.fiber.gz
|
||||
style.css
|
||||
src/ent/*
|
||||
!src/ent/schema/
|
||||
!src/ent/generate.go
|
||||
.env
|
||||
/articles
|
||||
TODO.md
|
||||
pocketbase
|
||||
pb_data
|
||||
mathesar*
|
||||
/database/
|
||||
/src/.env
|
||||
*_templ.go*
|
||||
*_templ*
|
||||
src/frontend/static/css/style.css
|
||||
src/frontend/static/images
|
||||
pb.py
|
||||
*.py
|
||||
*.override.yml
|
||||
BLOG*
|
||||
local_*
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
docker/tor
|
||||
docker/i2p
|
||||
!docker/i2p/tunnels.conf
|
@ -1,3 +0,0 @@
|
||||
src/ent/*
|
||||
!src/ent/schema/
|
||||
!src/ent/generate.go
|
10
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"a-h.templ",
|
||||
"davidanson.vscode-markdownlint",
|
||||
"bradlc.vscode-tailwindcss",
|
||||
"wayou.vscode-todo-highlight",
|
||||
"esbenp.prettier-vscode",
|
||||
"editorconfig.editorconfig"
|
||||
]
|
||||
}
|
30
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": null,
|
||||
"[templ]": {
|
||||
"editor.defaultFormatter": "a-h.templ"
|
||||
},
|
||||
"[go]": {
|
||||
"editor.defaultFormatter": "golang.go"
|
||||
},
|
||||
"[markdown]": {
|
||||
"editor.defaultFormatter": "DavidAnson.vscode-markdownlint"
|
||||
},
|
||||
"[yaml]": {
|
||||
"editor.defaultFormatter": "redhat.vscode-yaml"
|
||||
},
|
||||
"tailwindCSS.includeLanguages": {
|
||||
"templ": "html"
|
||||
},
|
||||
"emmet.includeLanguages": {
|
||||
"templ": "html"
|
||||
},
|
||||
"gopls": {
|
||||
"ui.semanticTokens": true,
|
||||
"formatting.gofumpt": true
|
||||
},
|
||||
"files.exclude": {
|
||||
"**/node_modules": true
|
||||
},
|
||||
"editor.tabSize": 2
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
# v2024-03-25
|
||||
|
||||
* Add changelog file
|
||||
* Migrate comments to Matrix. It is more widely used and more stable, also allows for web-less comments and chat.
|
||||
* Ensure service names are unique.
|
||||
* Improved logging.
|
30
README.md
@ -1,11 +1,29 @@
|
||||
# KYCNOT.ME OFFICIAL REPOSITORY
|
||||
# kycnot.me source code
|
||||
|
||||
This is the official repository of the KYCNOT.ME project.
|
||||
Source code of the [kycnot.me](https://kycnot.me) website (v2025).
|
||||
|
||||
## ToS Checker
|
||||
![banner](/src/frontend/static/assets/banner.webp)
|
||||
|
||||
The ToS checker is an automated ai-driven tool that checks the ToS of a website.
|
||||
## Project structure
|
||||
|
||||
## Official Tor Onionsite
|
||||
- `src`: Project code.
|
||||
- `frontend`: Generates the website HTML, CSS and JS.
|
||||
- `static`: Static files.
|
||||
- `templates`: [Templ](https://templ.guide/) templates.
|
||||
- `internal`: Internal backend packages:
|
||||
- `cache`: Cache implementation.
|
||||
- `database`: Database client.
|
||||
- `ent`: Database ent-go models.
|
||||
- `models`: Models.
|
||||
- `server`: Server/API implementation.
|
||||
- `utils`: Utilities.
|
||||
|
||||
`kycnotmezdiftahfmc34pqbpicxlnx3jbf5p7jypge7gdvduu7i6qjqd.onion`
|
||||
## Tech Stack
|
||||
|
||||
- [Go](https://go.dev/)
|
||||
- [Templ](https://templ.guide/)
|
||||
- [ent-go](https://entgo.io/)
|
||||
- [Tailwind CSS](https://tailwindcss.com/)
|
||||
- [MariaDB](https://mariadb.org/)
|
||||
- [Docker](https://www.docker.com/)
|
||||
- [just](https://just.systems/)
|
||||
|
@ -1,18 +1,10 @@
|
||||
name: "kycnotme_v2024"
|
||||
|
||||
services:
|
||||
website:
|
||||
labels:
|
||||
caddy: "kycnotme.localhost"
|
||||
caddy.reverse_proxy: "{{upstreams 4488}}"
|
||||
|
||||
pocketbase:
|
||||
database:
|
||||
ports:
|
||||
- 8090:80
|
||||
labels:
|
||||
caddy: "pocketbase.localhost"
|
||||
caddy.reverse_proxy: "{{upstreams 80}}"
|
||||
caddy.request_body.max_size: 10MB
|
||||
- 127.0.0.1:3306:3306
|
||||
volumes:
|
||||
- ./pocketbase/data:/pb_data
|
||||
- ./pocketbase/public:/pb_public
|
||||
- ./local_database/data:/var/lib/mysql:Z
|
||||
|
||||
app:
|
||||
ports:
|
||||
- 127.0.0.1:1337:1337
|
||||
|
@ -1,93 +1,49 @@
|
||||
name: "kycnotme_v2024"
|
||||
|
||||
networks:
|
||||
caddy:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
pb_data: {}
|
||||
pb_public: {}
|
||||
pb_migrations: {}
|
||||
database:
|
||||
|
||||
services:
|
||||
website:
|
||||
container_name: kycnotme-website
|
||||
build: ./src
|
||||
networks:
|
||||
caddy:
|
||||
default:
|
||||
volumes:
|
||||
- ./src/frontend/templates:/app/frontend/templates
|
||||
- ./src/frontend/static/proofs:/app/frontend/static/proofs
|
||||
env_file:
|
||||
- .env
|
||||
depends_on:
|
||||
pocketbase:
|
||||
condition: service_healthy
|
||||
labels:
|
||||
caddy: "${WEB_DOMAIN}"
|
||||
caddy.reverse_proxy: "{{upstreams 4488}}"
|
||||
caddy.header.Referrer-Policy: "no-referrer"
|
||||
caddy.header.Strict-Transport-Security: "max-age=31536000; includeSubdomains; preload;"
|
||||
caddy.encode: zstd gzip
|
||||
caddy.header.Onion-Location: ${ONION_ADDRESS}{path}
|
||||
ofelia.enabled: "true"
|
||||
ofelia.job-exec.toscheck.schedule: "0 0 1 * *"
|
||||
ofelia.job-exec.toscheck.command: "kycnotme -scrap"
|
||||
|
||||
pocketbase:
|
||||
image: spectado/pocketbase:latest
|
||||
container_name: kycnotme-pocketbase
|
||||
restart: always
|
||||
volumes:
|
||||
- pb_data:/pb_data
|
||||
- pb_public:/pb_public
|
||||
networks:
|
||||
caddy: {}
|
||||
default:
|
||||
aliases:
|
||||
- "database"
|
||||
labels:
|
||||
caddy: "${PB_DOMAIN}"
|
||||
caddy.reverse_proxy: "{{upstreams 80}}"
|
||||
caddy.request_body.max_size: 250MB
|
||||
caddy.header.X-Robots-Tag: "noindex"
|
||||
caddy.header.Strict-Transport-Security: "max-age=31536000; includeSubdomains; preload;"
|
||||
healthcheck: #optional (recommended) since v0.10.0
|
||||
test: wget --no-verbose --tries=1 --spider http://localhost:80/api/health || exit 1
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
tor:
|
||||
image: goldy/tor-hidden-service:latest
|
||||
profiles: ["tor"]
|
||||
container_name: kycnotme-tor
|
||||
restart: always
|
||||
networks:
|
||||
caddy: {}
|
||||
default: {}
|
||||
links:
|
||||
- website
|
||||
volumes:
|
||||
- ./docker/tor/hidden_service:/var/lib/tor/hidden_service
|
||||
database:
|
||||
image: mariadb:11
|
||||
restart: unless-stopped
|
||||
container_name: kycnot-database
|
||||
environment:
|
||||
SERVICE1_TOR_SERVICE_HOSTS: 80:website:4488
|
||||
SERVICE1_TOR_SERVICE_VERSION: '3'
|
||||
|
||||
i2pd:
|
||||
build:
|
||||
context: ./docker/i2p/
|
||||
profiles: ["i2p"]
|
||||
container_name: kycnotme-i2p
|
||||
restart: always
|
||||
networks:
|
||||
caddy: {}
|
||||
default: {}
|
||||
#ports:
|
||||
# - ":14447" # socks
|
||||
MARIADB_USER: ${MARIADB_USER:-kycnot}
|
||||
MARIADB_PASSWORD: ${MARIADB_PASSWORD:-kycnot}
|
||||
MARIADB_DATABASE: ${MARIADB_DATABASE:-kycnot}
|
||||
MARIADB_RANDOM_ROOT_PASSWORD: 1
|
||||
volumes:
|
||||
- ./docker/i2p/data:/root/.i2pd
|
||||
labels:
|
||||
caddy: ${I2P_ADDRESS}
|
||||
caddy.reverse_proxy: "website:4488"
|
||||
- database:/var/lib/mysql:Z
|
||||
- ./docker/database/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
start_period: 10s
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
app:
|
||||
build:
|
||||
context: ./src
|
||||
restart: unless-stopped
|
||||
container_name: kycnot-app
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
DATABASE_URI: "${MARIADB_USER:-kycnot}:${MARIADB_PASSWORD:-kycnot}@tcp(database:3306)/${MARIADB_DATABASE:-kycnot}?parseTime=True"
|
||||
SECRET_TOKEN: "${SECRET_TOKEN}"
|
||||
OPENAI_API_KEY: "${OPENAI_API_KEY}"
|
||||
ROOT_DIR: "/app"
|
||||
env_file: .env
|
||||
volumes:
|
||||
- ./src/frontend/static/images:/app/frontend/static/images
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"curl -k -s http://localhost:1337 | grep -i '<title>KYCNOT.ME</title>' || exit 1",
|
||||
]
|
||||
start_period: 10s
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
4
docker/database/init.sql
Normal file
@ -0,0 +1,4 @@
|
||||
GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED VIA unix_socket WITH GRANT OPTION;
|
||||
|
||||
CREATE DATABASE IF NOT EXISTS `nocodb`;
|
||||
GRANT ALL ON `nocodb`.* TO `kycnot`;
|
@ -1,10 +0,0 @@
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk --update --no-cache add i2pd && rm -rf /var/cache/apk/*
|
||||
|
||||
COPY i2pd.conf /i2p/i2pd.conf
|
||||
COPY tunnels.conf /i2p/tunnels.conf
|
||||
|
||||
#EXPOSE 14447
|
||||
|
||||
ENTRYPOINT ["i2pd", "--conf=/i2p/i2pd.conf"]
|
@ -1,12 +0,0 @@
|
||||
ipv4 = true
|
||||
ipv6 = false
|
||||
|
||||
bandwidth = P
|
||||
|
||||
daemon = false
|
||||
|
||||
tunconf = /i2p/tunnels.conf
|
||||
|
||||
log = file
|
||||
logfile = /i2p/log
|
||||
logclftime = true
|
14
docker/i2p/tunnels.conf
Normal file → Executable file
@ -1,11 +1,5 @@
|
||||
[KYCNotMeServer]
|
||||
[kycnotme]
|
||||
type = http
|
||||
host = caddy
|
||||
port = 80
|
||||
keys = KYCNotMe.dat
|
||||
|
||||
#[SOCKS]
|
||||
#type = socks
|
||||
#address = localhost
|
||||
#port = 14447
|
||||
#keys = SOCKS.dat
|
||||
host = app
|
||||
port = 1337
|
||||
keys = kycnotme.keys
|
||||
|
19
justfile
@ -1,19 +0,0 @@
|
||||
default: deploy
|
||||
|
||||
dev +command:
|
||||
docker compose -f docker-compose.yml -f docker-compose.dev.yml {{command}}
|
||||
|
||||
deploy build="":
|
||||
#!/bin/bash
|
||||
git pull
|
||||
|
||||
if [ -z "{{ build }}" ]; then
|
||||
build_flag=""
|
||||
else
|
||||
build_flag="--build"
|
||||
fi
|
||||
|
||||
docker compose up --pull=always -d $build_flag
|
||||
|
||||
if [ -z "{{ build }}" ]; then docker compose restart website; fi
|
||||
docker system prune -f
|
28
score.md
@ -1,28 +0,0 @@
|
||||
# What makes a good non-kyc service?
|
||||
|
||||
1. Accepts at least one anonymous payment method:
|
||||
- Bitcoin
|
||||
- Cash
|
||||
- Monero (even better)
|
||||
|
||||
|
||||
2. KYC Level
|
||||
0. BEST
|
||||
1. ACCEPTABLE
|
||||
2. NOT GOOD
|
||||
3. BAD
|
||||
|
||||
3. Verified
|
||||
1. Better if it is
|
||||
|
||||
4. TosReviews
|
||||
1. As few as possible warnings.
|
||||
|
||||
5. Onion available
|
||||
1. Good to have
|
||||
|
||||
6. Attributes
|
||||
- GOOD: bonus
|
||||
- INFO: nothing
|
||||
- WARNING: penalty
|
||||
- BAD: penalty
|
@ -1 +1,5 @@
|
||||
.env
|
||||
frontend/static/images
|
||||
images
|
||||
node_modules
|
||||
*_templ.go
|
||||
*_templ.txt
|
||||
|
4
src/.env.example
Normal file
@ -0,0 +1,4 @@
|
||||
DATABASE_URI="kycnot:kycnot@tcp(localhost:3306)/kycnot?parseTime=True"
|
||||
SECRET_TOKEN="FAKE_VALUE" # openssl rand -hex 32
|
||||
ROOT_DIR="FAKE_VALUE" # Path to the root of the project
|
||||
OPENAI_API_KEY="FAKE_VALUE"
|
@ -1,33 +1,34 @@
|
||||
FROM devopsworks/golang-upx:latest AS builder
|
||||
# Builder stage
|
||||
FROM golang:1.23-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN go mod tidy
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o kycnotme . && \
|
||||
upx kycnotme
|
||||
RUN chmod +x kycnotme
|
||||
|
||||
# Tailwind CSS compiler
|
||||
FROM node:latest AS tailwind
|
||||
RUN go install github.com/a-h/templ/cmd/templ@latest
|
||||
RUN templ generate -path ./frontend/templates/
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o kycnot .
|
||||
RUN chmod a+rx kycnot
|
||||
RUN mkdir -p /app/frontend/static/images
|
||||
|
||||
# Node stage
|
||||
FROM node:alpine AS node
|
||||
RUN apk add --no-cache ca-certificates tzdata
|
||||
WORKDIR /app
|
||||
COPY ./package.json .
|
||||
COPY ./package-lock.json .
|
||||
COPY ./tailwind.config.js .
|
||||
COPY ./frontend/ /app/
|
||||
COPY ./frontend/tailwind.config.js .
|
||||
COPY ./frontend/package.json ./frontend/package-lock.json ./
|
||||
COPY ./frontend/static ./static
|
||||
COPY ./frontend/templates ./templates
|
||||
RUN npm ci && \
|
||||
npx tailwindcss -i ./static/css/input.css -o ./static/css/style.css --minify
|
||||
|
||||
RUN npm i && \
|
||||
npx tailwindcss -i /app/static/css/input.css -o /app/style.css --minify
|
||||
|
||||
FROM alpine:latest AS certs
|
||||
RUN apk --update add ca-certificates
|
||||
|
||||
FROM scratch
|
||||
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
# Final stage
|
||||
FROM alpine:3 AS final
|
||||
WORKDIR /app
|
||||
COPY ./frontend /app/frontend
|
||||
COPY --from=tailwind /app/style.css /app/frontend/static/css/style.css
|
||||
COPY --from=builder /app/kycnotme /bin/usr/kycnotme
|
||||
ENV PATH="/bin/usr:${PATH}"
|
||||
COPY --from=builder /app/kycnot /app/kycnot
|
||||
COPY ./frontend/static /app/frontend/static
|
||||
COPY --from=node /app/static/css/style.css /app/frontend/static/css/style.css
|
||||
RUN apk add --no-cache curl
|
||||
|
||||
EXPOSE 4488
|
||||
ENTRYPOINT ["kycnotme"]
|
||||
ENV TZ="Europe/Warsaw"
|
||||
ENV PATH="/app:$PATH"
|
||||
|
||||
EXPOSE 1337
|
||||
CMD ["/app/kycnot", "serve"]
|
||||
|
@ -1,19 +0,0 @@
|
||||
package config
|
||||
|
||||
type Config struct {
|
||||
Dev bool
|
||||
Debug bool
|
||||
Cache bool
|
||||
Scraper bool
|
||||
ListenAddr string
|
||||
Donations Donations
|
||||
}
|
||||
|
||||
type Donations struct {
|
||||
Xmr string
|
||||
Btc string
|
||||
BtcSilent string
|
||||
Lnn string
|
||||
}
|
||||
|
||||
var Conf Config
|
@ -1,7 +0,0 @@
|
||||
package database
|
||||
|
||||
const (
|
||||
AttributeOpenSource = "l0p2hlenm8cm7jp"
|
||||
AttributeP2PNetwork = "lpkke4dygq0yoly"
|
||||
AttributeP2PTrading = "5bcqjb2xzbel9g9"
|
||||
)
|
@ -1,77 +0,0 @@
|
||||
package database
|
||||
|
||||
type Service struct {
|
||||
Category string `json:"category"`
|
||||
CollectionID string `json:"collectionId"`
|
||||
CollectionName string `json:"collectionName"`
|
||||
Comments []string `json:"comments,omitempty"`
|
||||
Created string `json:"created"`
|
||||
Description string `json:"description"`
|
||||
Expand map[string][]Attribute `json:"expand,omitempty"`
|
||||
Attributes []string `json:"attributes,omitempty"`
|
||||
ID string `json:"id"`
|
||||
KycLevel int `json:"kyc_level"`
|
||||
Listed bool `json:"listed"`
|
||||
LogoURL string `json:"logo_url"`
|
||||
Name string `json:"name"`
|
||||
OnionUrls []string `json:"onion_urls"`
|
||||
Pending bool `json:"pending"`
|
||||
Score int `json:"score"`
|
||||
Tags []string `json:"tags"`
|
||||
TosReviews []TosReview `json:"tos_reviews,omitempty"`
|
||||
LastTosReview string `json:"last_tos_review"`
|
||||
TosUrls []string `json:"tos_urls"`
|
||||
Type string `json:"type"`
|
||||
Referral string `json:"referral"`
|
||||
Updated string `json:"updated"`
|
||||
Urls []string `json:"urls"`
|
||||
Verified bool `json:"verified"`
|
||||
Xmr bool `json:"xmr"`
|
||||
Btc bool `json:"btc"`
|
||||
Fiat bool `json:"fiat"`
|
||||
Cash bool `json:"cash"`
|
||||
Lightning bool `json:"lightning"`
|
||||
Notes []string `json:"notes,omitempty"`
|
||||
SupportMethods []Support `json:"support"`
|
||||
}
|
||||
|
||||
type Support struct {
|
||||
Platform string `json:"platform"`
|
||||
Link string `json:"Link"`
|
||||
}
|
||||
|
||||
type TosReview struct {
|
||||
Title string `json:"title"`
|
||||
Details string `json:"details"`
|
||||
Section string `json:"section"`
|
||||
Warning bool `json:"warning"`
|
||||
Reference string `json:"reference"`
|
||||
}
|
||||
|
||||
type Attribute struct {
|
||||
CollectionID string `json:"collectionId"`
|
||||
CollectionName string `json:"collectionName"`
|
||||
Created string `json:"created"`
|
||||
Description string `json:"description"`
|
||||
ID string `json:"id"`
|
||||
Rating string `json:"rating"`
|
||||
Title string `json:"title"`
|
||||
Updated string `json:"updated"`
|
||||
}
|
||||
|
||||
type Announcement struct {
|
||||
Title string
|
||||
Body string
|
||||
Link string
|
||||
Warning bool
|
||||
Active bool
|
||||
}
|
||||
|
||||
type Change struct {
|
||||
Created string `json:"created"`
|
||||
Summary string `json:"summary"`
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Updated string `json:"updated"`
|
||||
Expand map[string]Service `json:"expand,omitempty"`
|
||||
}
|
@ -1,220 +0,0 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/pluja/pocketbase"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type PbClient struct {
|
||||
Client *pocketbase.Client
|
||||
}
|
||||
|
||||
var Pb *PbClient
|
||||
|
||||
// InitPocketbase initializes the Pocketbase client
|
||||
func InitPocketbase() error {
|
||||
// Initialize Pb if not already done
|
||||
if Pb == nil {
|
||||
Pb = &PbClient{}
|
||||
}
|
||||
|
||||
// Create a new pocketbase client
|
||||
Pb.Client = pocketbase.NewClient(os.Getenv("PB_URL"),
|
||||
pocketbase.WithAdminEmailPassword(os.Getenv("PB_ADMIN_EMAIL"), os.Getenv("PB_ADMIN_PASSWORD")))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetServices retrieves services from the pocketbase client
|
||||
func (p *PbClient) GetServices(filters, sort string) ([]Service, error) {
|
||||
|
||||
collection := pocketbase.CollectionSet[Service](p.Client, "services")
|
||||
params := pocketbase.ParamsList{
|
||||
Page: 1,
|
||||
Size: 200,
|
||||
Expand: "attributes",
|
||||
Fields: "*,expand.attributes.*",
|
||||
}
|
||||
|
||||
if filters != "" {
|
||||
params.Filters = filters
|
||||
}
|
||||
|
||||
if sort != "" {
|
||||
params.Sort = sort
|
||||
}
|
||||
|
||||
response, err := collection.List(params)
|
||||
if err != nil {
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
return response.Items, nil
|
||||
}
|
||||
|
||||
func (p *PbClient) GetChanges() ([]Change, error) {
|
||||
|
||||
collection := pocketbase.CollectionSet[Change](p.Client, "changes")
|
||||
params := pocketbase.ParamsList{
|
||||
Page: 1,
|
||||
Size: 200,
|
||||
Expand: "service",
|
||||
Fields: "*,expand.service.*",
|
||||
Sort: "-created",
|
||||
}
|
||||
|
||||
response, err := collection.List(params)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("err")
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
return response.Items, nil
|
||||
}
|
||||
|
||||
func (p *PbClient) GetServiceByNameOrUrl(id string) (*Service, error) {
|
||||
collection := pocketbase.CollectionSet[Service](p.Client, "services")
|
||||
params := pocketbase.ParamsList{
|
||||
Page: 1,
|
||||
Size: 1,
|
||||
Fields: "*,expand.attributes.*",
|
||||
Expand: "attributes",
|
||||
Filters: fmt.Sprintf("((name='%v') || (urls~'%v'))", id, id),
|
||||
}
|
||||
|
||||
response, err := collection.List(params)
|
||||
if err != nil {
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
if len(response.Items) > 0 {
|
||||
service := response.Items[0]
|
||||
|
||||
// Sort attributes by rating
|
||||
sort.SliceStable(service.Expand["attributes"], func(i, j int) bool {
|
||||
ratingOrder := map[string]int{
|
||||
"bad": 4,
|
||||
"warn": 3,
|
||||
"good": 2,
|
||||
"info": 1,
|
||||
}
|
||||
return ratingOrder[service.Expand["attributes"][i].Rating] > ratingOrder[service.Expand["attributes"][j].Rating]
|
||||
})
|
||||
return &service, nil
|
||||
} else {
|
||||
return nil, errors.New("service not found")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (p *PbClient) GetServiceById(id string) (*Service, error) {
|
||||
collection := pocketbase.CollectionSet[Service](p.Client, "services")
|
||||
params := pocketbase.ParamsList{
|
||||
Fields: "*,expand.attributes.*",
|
||||
Expand: "attributes",
|
||||
}
|
||||
|
||||
response, err := collection.OneWithParams(id, params)
|
||||
if err != nil {
|
||||
return nil, errors.New("service not found")
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func (p *PbClient) CreateService(service Service) error {
|
||||
collection := pocketbase.CollectionSet[Service](p.Client, "services")
|
||||
|
||||
_, err := collection.Create(service)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "validation_not_unique") {
|
||||
return errors.New("a service with this name already exsits, check out /pending page")
|
||||
}
|
||||
log.Debug().Err(err).Msg("could not create service")
|
||||
return errors.New("could not create service")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PbClient) UpdateService(id string, service Service) error {
|
||||
collection := pocketbase.CollectionSet[Service](p.Client, "services")
|
||||
|
||||
err := collection.Update(id, service)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not update: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PbClient) GetAttribute(id string) (*Attribute, error) {
|
||||
collection := pocketbase.CollectionSet[Attribute](p.Client, "attributes")
|
||||
|
||||
response, err := collection.One(id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get service: %v", err)
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func (p *PbClient) GetAttributes(filters, sort string) ([]Attribute, error) {
|
||||
collection := pocketbase.CollectionSet[Attribute](p.Client, "attributes")
|
||||
params := pocketbase.ParamsList{
|
||||
Page: 1,
|
||||
Size: 250,
|
||||
}
|
||||
|
||||
if filters != "" {
|
||||
params.Filters = filters
|
||||
}
|
||||
|
||||
if sort != "" {
|
||||
params.Sort = sort
|
||||
}
|
||||
|
||||
response, err := collection.List(params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not list: %s", err)
|
||||
}
|
||||
|
||||
return response.Items, nil
|
||||
}
|
||||
|
||||
func (p *PbClient) CreateAttribute(attribute Attribute) error {
|
||||
collection := pocketbase.CollectionSet[Attribute](p.Client, "attributes")
|
||||
|
||||
_, err := collection.Create(attribute)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create attribute: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PbClient) GetAnnouncement() *Announcement {
|
||||
collection := pocketbase.CollectionSet[Announcement](p.Client, "announcements")
|
||||
params := pocketbase.ParamsList{
|
||||
Page: 1,
|
||||
Size: 1,
|
||||
Filters: "active=true",
|
||||
}
|
||||
|
||||
response, err := collection.List(params)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(response.Items) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &response.Items[0]
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
# APP
|
||||
ROOT_DIR="./"
|
||||
LISTEN_ADDR="127.0.0.1:4488"
|
||||
POW_DIFFICULTY=4
|
||||
POW_INCREASE_EVERY_CHALLENGES=20
|
||||
|
||||
# DONATIONS
|
||||
XMR_ADDRESS="82xxxx28_monero_address_ZU2xxxx"
|
||||
BTC_ADDRESS="bc1q_bitcoin_address"
|
||||
LNN_ADDRESS="https://getalby.com/p/username"
|
||||
|
||||
# OPEN_AI
|
||||
OPENAI_API_KEY="sk-xxxxx"
|
||||
ANTHROPIC_API_KEY="sk-ant-xxxx"
|
||||
|
||||
# CRAWLER
|
||||
CRAWLER_API_URL="http://localhost:3011"
|
||||
|
||||
# POCKETBASE
|
||||
PB_URL="http://localhost:8022"
|
||||
PB_ADMIN_EMAIL="user@pocketbase.io"
|
||||
PB_ADMIN_PASSWORD="password"
|
1
src/frontend/.nvmrc
Normal file
@ -0,0 +1 @@
|
||||
22
|
777
src/package-lock.json → src/frontend/package-lock.json
generated
16
src/frontend/package.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"@iconify-json/jam": "^1.2.1",
|
||||
"@iconify-json/tabler": "^1.2.7",
|
||||
"@iconify/tailwind": "^1.1.3",
|
||||
"@tailwindcss/forms": "^0.5.9",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"concurrently": "^8.2.2",
|
||||
"tailwindcss": "^3.4.14"
|
||||
},
|
||||
"scripts": {
|
||||
"tailwind:dev": "tailwindcss -i static/css/input.css -o static/css/style.css --watch",
|
||||
"tailwind:build": "tailwindcss -i static/css/input.css -o static/css/style.css --minify",
|
||||
"build": "npm run tailwind:build"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 421 KiB |
24
src/frontend/static/assets/gradient.svg
Normal file
@ -0,0 +1,24 @@
|
||||
<svg width="2048" height="1080" viewBox="0 0 2048 1080" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="2048" height="1080" fill="#111" />
|
||||
<g filter="url(#blur)">
|
||||
<circle cx="2169.5" cy="544.5" r="634.5" stroke="#415023" stroke-width="200" />
|
||||
<circle cx="-263.5" cy="420.5" r="587.5" stroke="#415023" stroke-width="200" />
|
||||
</g>
|
||||
<rect width="2048" height="1080" filter="url(#noise)" />
|
||||
<defs>
|
||||
<filter id="blur" x="-1325.3" y="-641.3" width="4603.6" height="2294.6" filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
|
||||
<feGaussianBlur stdDeviation="187.15" result="effect1_foregroundBlur_1_4" />
|
||||
</filter>
|
||||
<filter id="noise">
|
||||
<feTurbulence type="fractalNoise" baseFrequency="0.3" numOctaves="2" result="noise" />
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0
|
||||
0 0.4 0 0 0
|
||||
0 0 0 0 0
|
||||
0 0 0 0.09 0" result="greenNoise" />
|
||||
<feBlend mode="multiply" in="SourceGraphic" in2="greenNoise" />
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.9 MiB |
Before Width: | Height: | Size: 18 KiB |
1
src/frontend/static/assets/logo_wide-2.svg
Normal file
After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 24 KiB |
@ -1 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_ZCsl{animation:spinner_qV4G 1.2s cubic-bezier(0.52,.6,.25,.99) infinite}.spinner_gaIW{animation-delay:.6s}@keyframes spinner_qV4G{0%{r:0;opacity:1}100%{r:11px;opacity:0}}</style><circle class="spinner_ZCsl" cx="12" cy="12" r="0"/><circle class="spinner_ZCsl spinner_gaIW" cx="12" cy="12" r="0"/></svg>
|
Before Width: | Height: | Size: 400 B |
@ -2,6 +2,9 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'inter';
|
||||
src: url('../fonts/inter.ttf') format('truetype');
|
||||
|
BIN
src/frontend/static/fonts/garamond.ttf
Normal file
@ -1,69 +1,103 @@
|
||||
async function computeProof(challenge, difficulty) {
|
||||
let nonce = 0;
|
||||
const leadingZeros = '0'.repeat(difficulty);
|
||||
const POW = {
|
||||
challenge: null,
|
||||
difficulty: null,
|
||||
lastNonce: null,
|
||||
|
||||
async fetchChallenge() {
|
||||
const response = await fetch('/api/pow')
|
||||
if (!response.ok) throw new Error('Failed to fetch challenge')
|
||||
const data = await response.json()
|
||||
if (data.error) throw new Error(data.error)
|
||||
this.challenge = data.challenge
|
||||
this.difficulty = data.difficulty
|
||||
},
|
||||
|
||||
async computeProof(challenge, difficulty) {
|
||||
const leadingZeros = '0'.repeat(difficulty)
|
||||
const encoder = new TextEncoder()
|
||||
let nonce = 0
|
||||
while (true) {
|
||||
const candidate = `${challenge}:${nonce}`;
|
||||
const hash = new TextEncoder().encode(candidate);
|
||||
const hashArrayBuffer = await crypto.subtle.digest('SHA-256', hash);
|
||||
const candidate = `${challenge}:${nonce}`
|
||||
const hash = encoder.encode(candidate)
|
||||
const hashArrayBuffer = await crypto.subtle.digest('SHA-256', hash)
|
||||
const hashHex = Array.from(new Uint8Array(hashArrayBuffer))
|
||||
.map(b => b.toString(16).padStart(2, '0'))
|
||||
.join('');
|
||||
|
||||
.map((b) => b.toString(16).padStart(2, '0'))
|
||||
.join('')
|
||||
if (hashHex.startsWith(leadingZeros)) {
|
||||
return nonce;
|
||||
console.log(hashHex)
|
||||
return nonce.toString()
|
||||
}
|
||||
nonce++;
|
||||
await new Promise(resolve => setTimeout(resolve, 0)); // Yield control to avoid freezing the UI
|
||||
nonce++
|
||||
if (nonce % 1000 === 0) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 0))
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
function startPow() {
|
||||
const element = document.querySelector('#start-pow');
|
||||
element.addEventListener('click', async () => {
|
||||
const difficulty = parseInt(element.getAttribute('data-pow-d'), 10);
|
||||
const challenge = element.getAttribute('data-pow-c');
|
||||
const id = element.getAttribute('data-pow');
|
||||
async verifyProof(challenge, nonce) {
|
||||
const url = `/api/pow/verify/${encodeURIComponent(challenge)}/${encodeURIComponent(nonce)}`
|
||||
const response = await fetch(url, { method: 'GET' })
|
||||
if (!response.ok) throw new Error('Network response was not ok')
|
||||
return response.json()
|
||||
},
|
||||
|
||||
const spinner = document.querySelector('#pow-spinner');
|
||||
spinner.classList.remove('hidden');
|
||||
element.classList.remove('bg-blue-900');
|
||||
element.classList.add('bg-gray-700');
|
||||
const text = document.querySelector('#pow-text');
|
||||
text.innerText = 'Computing...';
|
||||
updateUI(element, state) {
|
||||
const spinner = document.querySelector('#pow-spinner')
|
||||
const text = document.querySelector('#pow-text')
|
||||
const submit = document.querySelector('#submit-btn')
|
||||
const nonceInput = document.querySelector('#pow-nonce')
|
||||
const idInput = document.querySelector('#pow-id')
|
||||
element.className = 'pow-button'
|
||||
spinner.classList.toggle('hidden', state !== 'computing')
|
||||
element.classList.add(
|
||||
state === 'computing'
|
||||
? 'bg-gray-700'
|
||||
: state === 'verified'
|
||||
? 'bg-lime-700'
|
||||
: state === 'failed'
|
||||
? 'bg-red-700'
|
||||
: 'bg-blue-900'
|
||||
)
|
||||
if (state === 'verified') {
|
||||
element.classList.add('disabled')
|
||||
nonceInput.value = this.lastNonce
|
||||
idInput.value = this.challenge
|
||||
}
|
||||
element.classList.toggle('cursor-pointer', state !== 'verified')
|
||||
text.textContent =
|
||||
state === 'computing'
|
||||
? 'Computing...'
|
||||
: state === 'verified'
|
||||
? '✅ Verified!'
|
||||
: state === 'failed'
|
||||
? '❌ Failed!'
|
||||
: 'An error occurred!'
|
||||
submit.classList.toggle('hidden', state !== 'verified')
|
||||
},
|
||||
|
||||
async startPow() {
|
||||
const element = document.querySelector('#start-pow')
|
||||
if (!element) throw new Error('Start POW element not found')
|
||||
this.updateUI(element, 'computing')
|
||||
try {
|
||||
const nonce = await computeProof(challenge, difficulty);
|
||||
|
||||
spinner.classList.add('hidden');
|
||||
|
||||
const url = `/api/g/pow/verify/${id}/${nonce}`;
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.valid) {
|
||||
element.classList.remove('bg-gray-700');
|
||||
element.classList.remove('cursor-pointer');
|
||||
element.classList.add('bg-lime-700');
|
||||
element.classList.add('disabled');
|
||||
text.innerText = '✅ Verified!';
|
||||
|
||||
// Show submit button
|
||||
const submit = document.querySelector('#submit-btn');
|
||||
submit.classList.remove('hidden');
|
||||
|
||||
// Set pow-nonce form input value to nonce
|
||||
const nonceInput = document.querySelector('#pow-nonce');
|
||||
nonceInput.value = nonce;
|
||||
} else {
|
||||
element.classList.remove('bg-gray-700');
|
||||
element.classList.add('bg-red-700');
|
||||
text.innerText = '❌ Failed!';
|
||||
}
|
||||
await this.fetchChallenge()
|
||||
this.lastNonce = await this.computeProof(this.challenge, this.difficulty)
|
||||
const response = await this.verifyProof(this.challenge, this.lastNonce)
|
||||
console.log(response)
|
||||
const valid = response.status === 200 && response.valid === true
|
||||
this.updateUI(element, valid ? 'verified' : 'failed')
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
spinner.classList.add('hidden');
|
||||
text.innerText = 'An error occurred!';
|
||||
console.error('Error:', error)
|
||||
this.updateUI(element, 'error')
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
init() {
|
||||
const element = document.querySelector('#start-pow')
|
||||
if (element) {
|
||||
element.addEventListener('click', () => this.startPow())
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => POW.init())
|
||||
|
@ -35,7 +35,7 @@ func (s *Server) handleGetFormPage(c *fiber.Ctx) error {
|
||||
|
||||
### HTML
|
||||
|
||||
```
|
||||
```html
|
||||
<form action="" method="POST">
|
||||
<noscript>
|
||||
<p class="my-2 font-bold text-yellow-500 uppercase">
|
@ -1,13 +0,0 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mDMEZczexBYJKwYBBAHaRw8BAQdA+X+cNkOv5SmauKLLw+xcEkcDQjVubZ/4Xj3d
|
||||
5DNvgru0F3BsdWphIDxhZG1pbkBreWNub3QubWU+iJMEExYKADsWIQQEPOrx9H8d
|
||||
Txv0tFhweQHG2o41CgUCZczexAIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIX
|
||||
gAAKCRBweQHG2o41CjwVAQDpcxgeXK+2KiVzMkmLCXiAYU0hRhQmA4xwXDkqYxn7
|
||||
dwD+KzHpcnTwnrK5ZLn3+ti9DVeURTv1lFf9TVZTKgovOAy4OARlzN7EEgorBgEE
|
||||
AZdVAQUBAQdAvrCLlUmBr/RswvfC4hOGa5Som7CGQp0WzpkyETZmRh0DAQgHiHgE
|
||||
GBYKACAWIQQEPOrx9H8dTxv0tFhweQHG2o41CgUCZczexAIbDAAKCRBweQHG2o41
|
||||
ClZ1AQCwZ1XrRYLuM9d5mLXzbZVRjb5INoVXFrZbx9ZkAxKgFAD/dmJI/bUxPcVZ
|
||||
f6cwP2HYnxD/i2C6ltaLK0SRrxI2XAM=
|
||||
=Tnvi
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 26 KiB |
@ -1,35 +0,0 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
BITCOIN BLOCK HEIGHT: 865573
|
||||
MONERO BLOCK HEIGHT: 3258771
|
||||
|
||||
CAUTION: Always begin by testing the service with minimal amounts. For larger transactions, divide them into smaller batches rather than processing the entire amount at once. This approach helps mitigate potential risks and verify consistent service performance.
|
||||
|
||||
exch.cx service has been successfully tested.
|
||||
|
||||
- - I create an exchange: 0.00097516 BTC->LTC
|
||||
- https://kycnot.me/static/proofs/exch/create_exchange.webp
|
||||
- https://kycnot.me/static/proofs/exch/exchange_created.webp
|
||||
- - I send the funds to the shown address
|
||||
- INPUT TXID: a4abb6b785c8f4e356971c204aad06fe9c6da1be7ed0bbf33ff370ba78cd9d23
|
||||
- - The funds are detected quickly by exch.
|
||||
- https://kycnot.me/static/proofs/exch/exchange_confirm_input.webp
|
||||
- - After some time, the input is confirmed (1 confirmation)
|
||||
- - The exchange sends the funds to the receive address:
|
||||
- https://kycnot.me/static/proofs/exch/exchange_confirm_output.webp
|
||||
- OUTPUT TXID: 5964e047d85275f85a7a9d2e527f09235ce6ba4205222e4ccab8e8c86a5914c0
|
||||
- - Exchange is completed successfully:
|
||||
- https://kycnot.me/static/proofs/exch/exchange_sent.webp
|
||||
|
||||
NOTE: The output amount was higher than the initially calculated amount due to price fluctuation during the exchange.
|
||||
|
||||
DISCLAIMER: This proof only demonstrates that the service was operational during my testing. It does not guarantee future reliability or legitimacy. The service may become unreliable or fraudulent over time. This verification is based solely on current observations and should not be considered a long-term endorsement. Tests may be performed on a regular basis.
|
||||
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iHUEARYKAB0WIQQEPOrx9H8dTxv0tFhweQHG2o41CgUCZwz0yQAKCRBweQHG2o41
|
||||
CpwsAP4jFfRdeDOQ6DwUDcx1fmjoQzr0Cs134n17zWc9XPNAOAEAmM+S/4C5vt4a
|
||||
rapX21onZr00pQFmAhpQUOGvknDDIww=
|
||||
=GTzI
|
||||
-----END PGP SIGNATURE-----
|
Before Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 52 KiB |
@ -1,23 +0,0 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
BITCOIN BLOCK HEIGHT: 865188
|
||||
MONERO BLOCK HEIGHT: 3256820
|
||||
|
||||
ppq.ai service has been successfully tested.
|
||||
|
||||
* Add funds with Monero:
|
||||
https://kycnot.me/static/proofs/ppq/before_payment.png
|
||||
* Sent funds from wallet. Received almost instantly.
|
||||
https://kycnot.me/static/proofs/ppq/payment_received.png
|
||||
* Test chatting and generating images:
|
||||
https://kycnot.me/static/proofs/ppq/works.png
|
||||
|
||||
DISCLAIMER: This proof only demonstrates that the service was operational during my testing. It does not guarantee future reliability or legitimacy. The service may become unreliable or fraudulent over time. This verification is based solely on current observations and should not be considered a long-term endorsement. Tests may be performed on a regular basis.
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iHUEARYKAB0WIQQEPOrx9H8dTxv0tFhweQHG2o41CgUCZwz01QAKCRBweQHG2o41
|
||||
CjNTAQCDDSG/BEesIy+3y3esIx0OR4M+mj2Av6Sp/oDnY6t1wQD9Fy6yWFJoE4j6
|
||||
I5hVHpTvQoePgWPH4TL3s7B7tZZJ0AM=
|
||||
=BF3i
|
||||
-----END PGP SIGNATURE-----
|
Before Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 68 KiB |
@ -1,19 +0,0 @@
|
||||
BITCOIN BLOCK HEIGHT: 865186
|
||||
MONERO BLOCK HEIGHT: 3256808
|
||||
|
||||
simsup.net service has been successfully tested.
|
||||
|
||||
* Bought a Data-Only Esim on simsup.net:
|
||||
https://kycnot.me/static/proofs/simsup/order.png
|
||||
* I received an order confirmation mail, however the esim was not provided due to some issue:
|
||||
https://kycnot.me/static/proofs/simsup/mail.png
|
||||
* I contacted with support (first time I spoke to them):
|
||||
https://kycnot.me/static/proofs/simsup/telegram.png
|
||||
* They were quickly responsive and solved the issue.
|
||||
* Sim data was provided:
|
||||
https://kycnot.me/static/proofs/simsup/mail_2.png
|
||||
https://kycnot.me/static/proofs/simsup/esim.png
|
||||
* Configured the esim on my device
|
||||
* Data was available and it worked fine
|
||||
|
||||
DISCLAIMER: This proof only demonstrates that the service was operational during my testing. It does not guarantee future reliability or legitimacy. The service may become unreliable or fraudulent over time. This verification is based solely on current observations and should not be considered a long-term endorsement. Tests may be performed on a regular basis.
|
@ -1,29 +0,0 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
BITCOIN BLOCK HEIGHT: 865186
|
||||
MONERO BLOCK HEIGHT: 3256808
|
||||
|
||||
simsup.net service has been successfully tested.
|
||||
|
||||
* Bought a Data-Only Esim on simsup.net:
|
||||
https://kycnot.me/static/proofs/simsup/order.png
|
||||
* I received an order confirmation mail, however the esim was not provided due to some issue:
|
||||
https://kycnot.me/static/proofs/simsup/mail.png
|
||||
* I contacted with support (first time I spoke to them):
|
||||
https://kycnot.me/static/proofs/simsup/telegram.png
|
||||
* They were quickly responsive and solved the issue.
|
||||
* Sim data was provided:
|
||||
https://kycnot.me/static/proofs/simsup/mail_2.png
|
||||
https://kycnot.me/static/proofs/simsup/esim.png
|
||||
* Configured the esim on my device
|
||||
* Data was available and it worked fine
|
||||
|
||||
DISCLAIMER: This proof only demonstrates that the service was operational during my testing. It does not guarantee future reliability or legitimacy. The service may become unreliable or fraudulent over time. This verification is based solely on current observations and should not be considered a long-term endorsement. Tests may be performed on a regular basis.
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iHUEARYKAB0WIQQEPOrx9H8dTxv0tFhweQHG2o41CgUCZwz02wAKCRBweQHG2o41
|
||||
Cp+kAQCd/Cyl2kUEby7V78Vwtd3PI16TXROFDbC9wG3DwYJWOQD/R6fuCf0kMnTX
|
||||
yYK1/4p7MZxN9wdA2m2lgUl56x3wWAw=
|
||||
=Y/JU
|
||||
-----END PGP SIGNATURE-----
|
Before Width: | Height: | Size: 59 KiB |
29
src/frontend/tailwind.config.js
Normal file
@ -0,0 +1,29 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
const { addDynamicIconSelectors } = require('@iconify/tailwind');
|
||||
|
||||
module.exports = {
|
||||
content: ['./templates/**/*.{html,templ,js}', './static/js/*.js'],
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
samo: ['samo', 'monospace'],
|
||||
inter: ['inter', 'sans-serif'],
|
||||
},
|
||||
colors: {
|
||||
background: 'var(--kycnot-background)',
|
||||
primary: 'var(--kycnot-primary)',
|
||||
'primary-emphasis': 'var(--kycnot-primary-emphasis)',
|
||||
'primary-dark': 'var(--kycnot-primary-dark)',
|
||||
'primary-light': 'var(--kycnot-primary-light)',
|
||||
'kycnot-text': 'var(--kycnot-text)',
|
||||
'kycnot-text-fade': 'var(--kycnot-text-fade)',
|
||||
'kycnot-text-select': 'var(--kycnot-text-select)',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
require('@tailwindcss/typography'),
|
||||
require('@tailwindcss/forms'),
|
||||
addDynamicIconSelectors(),
|
||||
],
|
||||
};
|
7
src/frontend/templates/01-extra-icons.html
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- This file is to make TailwindCSS and Iconify load this extra icons, which are not directly used in any class-->
|
||||
|
||||
<i class="icon-[tabler--hash]"></i>
|
||||
<i class="icon-[tabler--mail]"></i>
|
||||
<i class="icon-[tabler--link]"></i>
|
||||
<i class="icon-[tabler--brand-mastodon]"></i>
|
||||
<i class="icon-[tabler--brand-telegram]"></i>
|
@ -1,652 +0,0 @@
|
||||
<style>
|
||||
article p {
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
article a {
|
||||
color: rgb(163 230 53);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.2rem;
|
||||
}
|
||||
|
||||
article div {
|
||||
padding-top: .5em;
|
||||
padding-bottom: .5em;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 0.3rem;
|
||||
font-weight: bold;
|
||||
font-family: samo;
|
||||
color: rgb(163 230 53);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 1.1em;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
h3::before {
|
||||
content: "~ ";
|
||||
}
|
||||
|
||||
article blockquote {
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-left: 1rem;
|
||||
border-left: 0.3rem solid rgb(163 230 53);
|
||||
color: rgb(142, 146, 150);
|
||||
}
|
||||
|
||||
code {
|
||||
background: #2b282872;
|
||||
border: 1px solid #494242;
|
||||
border-radius: 0.2rem;
|
||||
font-weight: bold;
|
||||
border-left: 3px solid #89f333;
|
||||
color: #d3cccc;
|
||||
font-family: samo;
|
||||
max-width: 100%;
|
||||
overflow: scorll;
|
||||
padding: 1em 1em;
|
||||
display: block;
|
||||
word-wrap: break-word;
|
||||
max-width: 90vw;
|
||||
margin-top: .2em;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="main" class="flex flex-col items-center justify-center">
|
||||
<div class="w-full max-w-4xl p-4">
|
||||
<div class="space-x-1 text-xs font-bold text-center lowercase text-lime-500 md:text-sm font-samo">
|
||||
<a href="#why">Why</a>
|
||||
·
|
||||
<a href="#what">What</a>
|
||||
·
|
||||
<a href="#btcxmr">Only Bitcoin and Monero?</a>
|
||||
·
|
||||
<a href="#listings">About listings</a>
|
||||
·
|
||||
<a href="#tos">ToS reviews</a>
|
||||
·
|
||||
<a href="#support">Support</a>
|
||||
·
|
||||
<a href="#contact">contact</a>
|
||||
·
|
||||
<a href="#comments">comments</a>
|
||||
·
|
||||
<a href="#transparency">transparency</a>
|
||||
·
|
||||
<a href="#privacy">privacy</a>
|
||||
.
|
||||
<a href="#api">api</a>
|
||||
·
|
||||
<a href="#disclaimer">disclaimer</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<article class="max-w-5xl [&>div]:px-4 [&>div]:py-1 font-inter">
|
||||
<div class="m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id="why" class="font-bold text-lime-400">why kycnot.me?</h2>
|
||||
<p>
|
||||
Cryptocurrencies were created to revolutionize the way we pay for goods
|
||||
and services, aiming to eliminate reliance on centralized entities such
|
||||
as banks and governments that control our economy.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Exchanges that enforce KYC (Know Your Customer) operate similarly to traditional banks. Users are
|
||||
required to provide identification, such as a photo of their ID, to use
|
||||
these exchanges. Moreover, most of these exchanges are centralized,
|
||||
meaning that users do not own their keys. In short, this implies that
|
||||
the cryptocurrencies belong to the exchange and not the user. These
|
||||
requirements go against the decentralized and self-sovereign nature of cryptocurrencies.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
With KYCNOT.ME, I hope to provide people with trustworthy alternatives for buying, exchanging, trading, and
|
||||
using cryptocurrencies
|
||||
without having to disclose their identity, thus preserving the right to privacy. I want to help preserve the
|
||||
original
|
||||
ethos of cryptocurrencies.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id="what" class="font-bold text-lime-400">what's KYC?</h2>
|
||||
<div class="space-y-2">
|
||||
<p>
|
||||
<strong>KYC</strong> stands for <strong>"Know Your Customer"</strong>,
|
||||
a process designed to protect financial institutions against fraud,
|
||||
corruption, money laundering and terrorist financing. Or at least this
|
||||
is what they want you to believe.
|
||||
</p>
|
||||
<p>
|
||||
The truth is that KYC is a direct
|
||||
attack on our privacy and puts us in disadvantage against the
|
||||
governments. True criminals don't care about KYC policies. True
|
||||
criminals know perfectly how to avoid such policies. In fact, they
|
||||
normally use the FIAT system and don't even need to use
|
||||
cryptocurrencies. Banks are the biggest money launders, the
|
||||
<a rel="noreferrer"
|
||||
href="https://www.reuters.com/business/hsbc-fined-85-mln-anti-money-laundering-failings-2021-12-17/">HSBC
|
||||
scandal</a>,
|
||||
<a rel="noreferrer"
|
||||
href="https://www.reuters.com/article/us-nordea-bnk-moneylaundering-idUSKCN1QL11S">Nordea</a>
|
||||
or
|
||||
<a rel="noreferrer"
|
||||
href="https://www.reuters.com/article/us-europe-moneylaundering-swedbank/swedbank-hit-with-record-386-million-fine-over-baltic-money-laundering-breaches-idUSKBN2163LU">Swedbank</a>
|
||||
are just some examples.
|
||||
</p>
|
||||
<p>
|
||||
Chainalysis found that only 0.34% of the transaction volume with cryptocurrencies in 2023 was attributable to
|
||||
criminal
|
||||
activity. Bitcoin's share of this is significantly lower with 25%. Illicit transactions with Euros accounted
|
||||
for 1% of
|
||||
the EU's GDP or €110 billion in 2010. <a
|
||||
href="https://www.chainalysis.com/blog/2024-crypto-crime-report-introduction/">[1]</a> <a
|
||||
href="https://transparency.eu/priority/financial-flows-crime/">[2]</a>
|
||||
</p>
|
||||
<p>
|
||||
KYC only affects small individuals like you and me. It is an annoying
|
||||
procedure that forces us to hand our personal information to a
|
||||
third party in order to buy, use or unlock our funds. We should start
|
||||
boycotting companies that enforce such practices. We should start using
|
||||
cryptocurrencies as they were intended to be used: without barriers.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h3 id="other-acronyms-of-interest">other acronyms of interest</h3>
|
||||
<div class="[&>span]:block space-y-2">
|
||||
<span><strong>SoF</strong>: Source of Funds</span>
|
||||
<span><strong>KYC</strong>: Know Your Customer</span>
|
||||
<span><strong>ToS</strong>: Terms of Service</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id="btcxmr">why only Bitcoin and Monero?</h2>
|
||||
<p>
|
||||
<strong>Bitcoin</strong>: it's the initial spark of the decentralized money.
|
||||
A solid project with a strong community. It is the most well-known and widespread cryptocurrency.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Monero</strong>: if digital cash was to exist, it should be like
|
||||
Monero. Fungible, private by design, fast and pretty low fees. Also, one
|
||||
of the oldest cryptocurrencies around with a very active community.
|
||||
</p>
|
||||
<p>
|
||||
No other currencies will be added. Most sites listed here also accept
|
||||
other cryptocurrencies, such as Ethereum or Litecoin.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id="listings">listings</h2>
|
||||
<h3 id="request">request</h3>
|
||||
<p>
|
||||
You can request a new listing by visiting the
|
||||
<a href="/request/service">Request</a> page. The request form requires javascript to avoid spam. <a
|
||||
href="#javascript">Read more about the PoW captcha in this section.</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="listing-process">listing process</h3>
|
||||
<p>
|
||||
The listing process is usually slow. I first need to review the service,
|
||||
read online reviews, gather evidence and history of good reviews /
|
||||
opinions, test it myself (i can't always do this), read the terms of
|
||||
service, privacy policy, etc...
|
||||
</p>
|
||||
|
||||
<p>
|
||||
I do this on my own free time, so I'm slow at it. If you feel like a
|
||||
<a href="/pending">pending service</a> deserves to be listed, you can
|
||||
<a href="#contact">contact me</a> and I will try to speed up the review
|
||||
process.
|
||||
</p>
|
||||
|
||||
<h3 id="attributes">what is an attribute?</h3>
|
||||
<p>
|
||||
An attribute is a feature that a service has. An attribute can be either
|
||||
good, a warning, bad or informational. Attributes are not limited, the
|
||||
list of attributes will grow if needed, you can see a full list of the
|
||||
attributes available on the Attributes page.
|
||||
</p>
|
||||
<p>
|
||||
You can click on any point to see a detailed description of what it
|
||||
means. The point page also shows all the listings that have that point.
|
||||
This is also a useful way to find listings that have a specific feature.
|
||||
</p>
|
||||
|
||||
<h3 id="search">search</h3>
|
||||
|
||||
<p>
|
||||
Filtering services in kycnot.me is very easy. In the main page, you will
|
||||
see 3 possible filters:
|
||||
</p>
|
||||
|
||||
<div class="[&>span]:block space-y-2">
|
||||
<span>
|
||||
<b>Type filter</b>: Lets you choose between seeing all the listings
|
||||
(default), only exchanges, or only services.
|
||||
</span>
|
||||
<span>
|
||||
<b>Search bar</b>: The search bar is the most powerful filter. You can
|
||||
use it to perform a full-text search on the listings. The search will
|
||||
look for the text you enter in the name, description, keywords and
|
||||
category. The search is not case-sensitive.
|
||||
</span>
|
||||
<span>
|
||||
<b>Currency filter</b>: Lets you choose between seeing all the
|
||||
listings (default), only listings that accept a certain currency. If
|
||||
you choose more than one option, it will show all the listings that
|
||||
accept all of the selected currencies.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h3 id="levels">kyc Levels</h3>
|
||||
|
||||
<p>
|
||||
KYCnot.me has a KYC level system. These levels allow you to quickly
|
||||
identify the kind of KYC practices a service may have. There are 4
|
||||
levels going from 0 to 3. The higher the level, the more invasive the
|
||||
KYC practices are.
|
||||
</p>
|
||||
|
||||
<h3 id="scoring">scoring</h3>
|
||||
|
||||
<p>
|
||||
Each listing has a score that is calculated based on the attributes that
|
||||
it has. The score does not reflect how good an exchange is overall, but
|
||||
it seeks to give a score in relation to its KYC practices. An exchange
|
||||
could have an awful UI/UX, but if it is very NO-KYC friendly, it will
|
||||
still get a high score.
|
||||
</p>
|
||||
|
||||
<p>The scoring algorithm is <a target="_blank"
|
||||
href="https://codeberg.org/pluja/kycnot.me/src/branch/main/src/utils/score.go">open source</a>,
|
||||
pull requests to improve it are welcome.
|
||||
It runs once every hour, meaning scores cannot be manually modified since they will be recalculated by the
|
||||
algorithm hourly. You can visit
|
||||
<a href="https://kycnot.me/api/v1/service/localmonero/summary">a service's score breakdown</a> to see how it is
|
||||
calculated.
|
||||
</p>
|
||||
|
||||
<h3 id="order">order</h3>
|
||||
|
||||
<p>
|
||||
The listings are sorted in a decreasing order by score. For listings
|
||||
that share the same score (tie), the order is random every time within
|
||||
that score range.
|
||||
</p>
|
||||
|
||||
<h3 id="pending">pending</h3>
|
||||
|
||||
<p>
|
||||
You can find the list of services that have been requested and are
|
||||
pending for approval here: <a href="/pending">/pending</a>
|
||||
</p>
|
||||
|
||||
<h3 id="verification">verification</h3>
|
||||
|
||||
<p class="mt-2">
|
||||
You will see that some services show a blue badge with a tick. This
|
||||
means that the service has been tested personally by me.
|
||||
</p>
|
||||
|
||||
<p class="mt-2">
|
||||
To check the service, I make a trade on the site, or test the service
|
||||
manually. With this, I can verify that the service does not perform KYC
|
||||
practices on regular basis, and that it is not a scam, at least at the
|
||||
time of the verification.
|
||||
</p>
|
||||
|
||||
<p class="mt-2">
|
||||
These checks are done randomly and without prior notice to the service.
|
||||
For this reason, and as the list is in constant growth, not all services
|
||||
have been verified yet and it takes me some time to verify them.
|
||||
</p>
|
||||
|
||||
<p class="mt-2">
|
||||
A verified service does not mean that the service is safe to use
|
||||
blindly, it just means that at the time of the verification, the service
|
||||
was not performing KYC practices on regular basis, and that it was not a
|
||||
scam. It is still recommended to do your own research before using any
|
||||
service, since I can't test all the services frequently enough.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id="tos">terms of service auto-reviews</h2>
|
||||
|
||||
<p>
|
||||
KYCnot.me features an AI-powered tool that automatically reviews Terms of Service (ToS) for all the different
|
||||
services. It breaks down the ToS content, highlights the main points, and translates them into
|
||||
easy-to-understand language, aiming to simplify the comprehension of any service's ToS.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For this, I am using OpenAI's GPT4-turbo model, which proved to be the
|
||||
most reliable and provides the best results.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Important note:</b> The automated tool generally delivers reliable and solid results. But it might flag false
|
||||
positives or irrelevant lines, if you find something's off, please <a href="#contact">contact me</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id="support">support this project</h2>
|
||||
|
||||
<p>
|
||||
If you like this project, or
|
||||
<a target="_blank" href="https://pluja.dev">any of my other projects</a>, you can support me through these
|
||||
methods:
|
||||
</p>
|
||||
|
||||
<div class="[&>span]:block space-y-6">
|
||||
<!-- Monero-->
|
||||
<span>
|
||||
<span class="flex items-center space-x-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 monero-filled" width="24" height="24"
|
||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M15 11.414v4.586a1 1 0 0 0 1 1l4.66 .001a10 10 0 0 1 -17.32 0l4.66 -.001l.117 -.007a1 1 0 0 0 .883 -.993v-4.585l2.293 2.292l.094 .083a1 1 0 0 0 1.32 -.083l2.293 -2.293zm2 -8.074a10 10 0 0 1 4.54 11.66h-4.54v-6c0 -.89 -1.077 -1.337 -1.707 -.707l-3.293 3.292l-3.293 -3.292l-.084 -.076c-.637 -.514 -1.623 -.07 -1.623 .783v6h-4.54a9.991 9.991 0 0 1 -.46 -3l.005 -.324a10 10 0 0 1 14.995 -8.336z"
|
||||
stroke-width="0" fill="currentColor" />
|
||||
</svg>
|
||||
<span class="font-bold uppercase">Monero</span>
|
||||
</span>
|
||||
|
||||
<p class="mt-1 text-xs text-white/50">
|
||||
> If your wallet supports <a rel="noreferrer" target="_blank" href="https://openalias.org/">OpenAlias</a>, you can use
|
||||
<span class="font-bold">kycnot.me</span> in the address field.
|
||||
</p>
|
||||
|
||||
<code>{{.Xmr}}</code>
|
||||
|
||||
<details class="my-2 mt-2 rounded-lg cursor-pointer">
|
||||
<summary class="flex items-center space-x-1 text-sm text-white/60">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 icon icon-tabler icon-tabler-qrcode" width="24"
|
||||
height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M4 4m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z" />
|
||||
<path d="M7 17l0 .01" />
|
||||
<path d="M14 4m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z" />
|
||||
<path d="M7 7l0 .01" />
|
||||
<path d="M4 14m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z" />
|
||||
<path d="M17 7l0 .01" />
|
||||
<path d="M14 14l3 0" />
|
||||
<path d="M20 14l0 .01" />
|
||||
<path d="M14 14l0 3" />
|
||||
<path d="M14 20l3 0" />
|
||||
<path d="M17 17l3 0" />
|
||||
<path d="M20 17l0 3" />
|
||||
</svg>
|
||||
<span class="underline"> Click for QR Code </span>
|
||||
</summary>
|
||||
<img class="my-4 size-60" src="/static/assets/xmr.webp" alt="Monero address QR code" />
|
||||
</details>
|
||||
</span>
|
||||
<!--End Monero-->
|
||||
|
||||
<hr class="border-gray-300/10">
|
||||
|
||||
<span>
|
||||
<span class="flex items-center space-x-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 bitcoin-filled" width="24" height="24"
|
||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M17 3.34a10 10 0 1 1 -15 8.66l.005 -.324a10 10 0 0 1 14.995 -8.336zm-4 2.66a1 1 0 0 0 -1 1h-1a1 1 0 0 0 -2 0a1 1 0 1 0 0 2v6a1 1 0 0 0 0 2c0 1.333 2 1.333 2 0h1a1 1 0 0 0 2 0v-.15c1.167 -.394 2 -1.527 2 -2.85l-.005 -.175a3.063 3.063 0 0 0 -.734 -1.827c.46 -.532 .739 -1.233 .739 -1.998c0 -1.323 -.833 -2.456 -2 -2.85v-.15a1 1 0 0 0 -1 -1zm.09 7c.492 0 .91 .437 .91 1s-.418 1 -.91 1h-2.09v-2h2.09zm0 -4c.492 0 .91 .437 .91 1c0 .522 -.36 .937 -.806 .993l-.104 .007h-2.09v-2h2.09z"
|
||||
stroke-width="0" fill="currentColor" />
|
||||
</svg>
|
||||
|
||||
<span>
|
||||
<span class="font-bold uppercase">Bitcoin</span>
|
||||
<span>via</span>
|
||||
<a target="_blank" class="font-bold capitalize" href="https://silentpayments.xyz">silent
|
||||
payments</a></span>
|
||||
</span>
|
||||
|
||||
<p class="mt-1 text-xs text-white/50">
|
||||
> If you want to donate without Silent Payments, request an address via any of the <a href="#contact">contact</a> methods.
|
||||
</p>
|
||||
|
||||
<code>{{.BtcSilent}}</code>
|
||||
|
||||
<details class="my-2 rounded-lg cursor-pointer">
|
||||
<summary class="flex items-center space-x-1 text-sm text-white/60">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 icon icon-tabler icon-tabler-qrcode" width="24"
|
||||
height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M4 4m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z" />
|
||||
<path d="M7 17l0 .01" />
|
||||
<path d="M14 4m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z" />
|
||||
<path d="M7 7l0 .01" />
|
||||
<path d="M4 14m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z" />
|
||||
<path d="M17 7l0 .01" />
|
||||
<path d="M14 14l3 0" />
|
||||
<path d="M20 14l0 .01" />
|
||||
<path d="M14 14l0 3" />
|
||||
<path d="M14 20l3 0" />
|
||||
<path d="M17 17l3 0" />
|
||||
<path d="M20 17l0 3" />
|
||||
</svg>
|
||||
<span class="underline"> Click for QR Code </span>
|
||||
</summary>
|
||||
<img class="my-4 size-60" src="/static/assets/btcsp.webp" alt="Bitcoin Address QR Code" />
|
||||
</details>
|
||||
</span>
|
||||
|
||||
<span class="pb-4 space-y-2">
|
||||
<span class="flex items-center space-x-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 tabler-bolt" width="24" height="24"
|
||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M13 3l0 7l6 0l-8 11l0 -7l-6 0l8 -11" />
|
||||
</svg>
|
||||
<a target="_blank" rel="noreferrer" href="{{.Lnn}}">Tip via Lightning Network</a>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id="contact">contact</h2>
|
||||
<p>
|
||||
If you have any queries or concerns, you can connect with me on any of the listed social media
|
||||
platforms below.
|
||||
</p>
|
||||
<p>
|
||||
For confidential communication (e2ee), please reach out via SimpleX link.
|
||||
</p>
|
||||
|
||||
<div class="[&>span]:block [&>span>a]:!no-underline [&>span>a]:font-bold space-y-2">
|
||||
<span>
|
||||
<a target="_blank" rel="noreferrer"
|
||||
href="https://simplex.chat/contact#/?v=2&smp=smp%3A%2F%2F0YuTwO05YJWS8rkjn9eLJDjQhFKvIYd8d4xG8X1blIU%3D%40smp8.simplex.im%2FcgKHYUYnpAIVoGb9lxb0qEMEpvYIvc1O%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAIW_JSq8wOsLKG4Xv4O54uT2D_l8MJBYKQIFj1FjZpnU%253D%26srv%3Dbeccx4yfxxbvyhqypaavemqurytl6hozr47wfc7uuecacjqdvwpw2xid.onion">💬 SimpleX Chat</a> <a
|
||||
class="mx-2 text-xs text-gray-400" href="https://simplex.chat">?</a>
|
||||
</span>
|
||||
<span>
|
||||
<a target="_blank" rel="noreferrer"
|
||||
href="https://njump.me/npub188x98j0r7l2fszeph6j7hj99h8xl07n989pskk5zd69d2fcksetq5mgcqf">🪶 Nostr</a> <a
|
||||
class="mx-2 text-xs text-gray-400" href="/nostr">?</a>
|
||||
</span>
|
||||
<span>
|
||||
<a target="_blank" rel="noreferrer" href="https://fosstodon.org/@kycnotme">🦣 Mastodon</a>
|
||||
</span>
|
||||
<span>
|
||||
<a target="_blank" rel="noreferrer" href="https://x.com/kycnot">🇽 Twitter (X)</a>
|
||||
</span>
|
||||
<span>
|
||||
<a target="_blank" rel="noreferrer" href="https://lemmy.world/u/pluja">🐭 Lemmy</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id="comments">comments</h2>
|
||||
|
||||
<p>
|
||||
Each service has a dedicated comments section. The comments are suppored
|
||||
by a self-hosted instance of <a rel="no-referrer" target="_blank" href="https://comentario.app">Comentario</a>. An open-source and lightweight (20kb) commenting engine.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To comment on a service's page, you can log in with Twitter, Github or Gitlab. Anonymous comments are also possible, but these need to be approved before being public to avoid abuse.
|
||||
</p>
|
||||
|
||||
<p>The <a rel="no-referrer" target="_blank" href="https://gitlab.com/commento/commento">source code</a> for Comentario is licensed under MIT license.</p>
|
||||
</div>
|
||||
|
||||
<div class="m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id="transparency">transparency</h2>
|
||||
|
||||
<p>
|
||||
In order to increase trust from visitors, KYCNOT.me strives to be as
|
||||
transparent as possible. Here are some of the ways in which I try to
|
||||
achieve this:
|
||||
</p>
|
||||
|
||||
<div class="[&>span]:block space-y-2">
|
||||
<span>
|
||||
* <a href="https://codeberg.org/pluja/kycnot.me">Open Source Code</a> -
|
||||
A commit history, and full disclosure of the scoring algorithm is
|
||||
provided.
|
||||
</span>
|
||||
<span>
|
||||
* Comment section on each page, available on a self-hosted <a href="https://comentario.app">Comentario</a> instance.
|
||||
</span>
|
||||
<span>* All changes are recorded on the <a href="/changelog">changelog</a></span>
|
||||
<span>* See any service's score breakdown: <a href="/api/v1/service/bisq/summary">bisq example</a></span>
|
||||
<span>* Open API to get all the listings data</span>
|
||||
<span>
|
||||
* Open scoring algorithm. All services go under the same algorithm,
|
||||
meaning that the score is not subjective.
|
||||
</span>
|
||||
<span>* Test proofs: I am slowly adding proofs for each verified service, providing a PGP signed proof that I have personally tested the service. To see a proof, click the "verified" badge next to a serivce's name, inside the service page.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id="privacy">privacy</h2>
|
||||
|
||||
<p>
|
||||
KYCNOT.me does not have trackers and never will. It does not make any
|
||||
third party connections from the frontend. No user data of any kind is
|
||||
collected. A "no-referrer" policy is enforced. Tor and I2P sites are available
|
||||
(check the footer).
|
||||
</p>
|
||||
|
||||
<h3 id="javascript">javascript</h3>
|
||||
|
||||
<p>
|
||||
KYCNOT.me does not require Javascript. Everything is rendered server-side.
|
||||
You can use KYCNOT.me with Javascript disabled.
|
||||
</p>
|
||||
|
||||
<p>Only things that do <b>require</b> JavaScript to be enabled are:</p>
|
||||
<div class="[&>span]:block space-y-2">
|
||||
<span>
|
||||
<b>Service Requests</b>: The Proof-Of-Work captcha, that I coded myself, needs
|
||||
JavaScript for the verfication. It is an <a rel="no-referrer" target="_blank"
|
||||
href="https://codeberg.org/pluja/kycnot.me/src/branch/main/src/frontend/static/js/pow.js">open-source</a>
|
||||
2.5kb javascript function.
|
||||
</span>
|
||||
<span>
|
||||
<b>Comments</b>: The comment section on each of the services, needs
|
||||
JavaScript since it needs to fetch and post to Matrix. The code that
|
||||
makes this interaction is also fully open source. Read more <a href="#comments">in this section.</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id="api">api</h2>
|
||||
|
||||
<p>KYCnot.me offers a public API to get its data.</p>
|
||||
<p>
|
||||
If you make use of the API data, you should mention kycnot.me as the source
|
||||
of the data.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>example:</b>
|
||||
<a href="/api/v1/service/bisq">/api/v1/service/bisq</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>example 2:</b>
|
||||
<a href="/api/v1/service/bisq.network">/api/v1/service/bisq.network</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>rate limit:</b>
|
||||
5req/min (with bursts of 5)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id="referrals">referrals</h2>
|
||||
|
||||
<p>
|
||||
<span>
|
||||
Referrals help me cover the site and maintenance costs. The default website link
|
||||
is the referral, if there is any. But there's always a referral-free
|
||||
option, that is shown with a
|
||||
</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="inline size-5 link-off" width="24" height="24"
|
||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M9 15l3 -3m2 -2l1 -1" />
|
||||
<path d="M11 6l.463 -.536a5 5 0 0 1 7.071 7.072l-.534 .464" />
|
||||
<path d="M3 3l18 18" />
|
||||
<path d="M13 18l-.397 .534a5.068 5.068 0 0 1 -7.127 0a4.972 4.972 0 0 1 0 -7.071l.524 -.463" />
|
||||
</svg>
|
||||
<span>icon. Feel free to choose.</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id="disclaimer">disclaimer</h2>
|
||||
|
||||
<p>
|
||||
This website does not provide any financial advice. Always do your
|
||||
own research before using any service. This site is for informational
|
||||
purposes only. I'm not responsible for any loss of funds or any other
|
||||
damage that may occur by using any of the services listed here. Use at
|
||||
your own risk.
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
580
src/frontend/templates/about.templ
Normal file
@ -0,0 +1,580 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
slugger "github.com/gosimple/slug"
|
||||
"os"
|
||||
)
|
||||
|
||||
// In golang, maps do not preserve order.
|
||||
var SectionsFunc = map[string]func() templ.Component{
|
||||
"why kycnot.me?": why,
|
||||
"what is kyc?": what,
|
||||
"why only btc and xmr?": onlyBtcXmr,
|
||||
"listings": listings,
|
||||
"automated tos reviews": automatedTosReviews,
|
||||
"support": support,
|
||||
"contact": contact,
|
||||
"comments": comments,
|
||||
"transparency": transparency,
|
||||
"privacy": privacy,
|
||||
"api": api,
|
||||
"disclaimer": disclaimer,
|
||||
}
|
||||
|
||||
// We use a slice to determine the order of keys.
|
||||
var sectionOrder = []string{
|
||||
"why kycnot.me?",
|
||||
"what is kyc?",
|
||||
"why only btc and xmr?",
|
||||
"listings",
|
||||
"automated tos reviews",
|
||||
"support",
|
||||
"contact",
|
||||
"comments",
|
||||
"transparency",
|
||||
"privacy",
|
||||
"api",
|
||||
"disclaimer",
|
||||
}
|
||||
|
||||
templ About() {
|
||||
@Base("About") {
|
||||
@inlineCss()
|
||||
<div id="main" class="flex flex-col justify-center items-center">
|
||||
<div class="p-4 w-full max-w-4xl">
|
||||
<div class="space-x-2 text-xs font-bold text-center text-lime-500 lowercase md:text-sm font-samo">
|
||||
for _, secTitle := range sectionOrder {
|
||||
<a href={ templ.SafeURL("#" + slugger.Make(secTitle)) }>{ secTitle }</a>
|
||||
·
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<article class="max-w-5xl [&>div]:px-4 [&>div]:py-1 font-inter">
|
||||
for _, secTitle := range sectionOrder {
|
||||
<div class="m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id={ slugger.Make(secTitle) } class="font-bold text-lime-400 text-md">{ secTitle }</h2>
|
||||
<div class="space-y-2">
|
||||
@SectionsFunc[secTitle]()
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</article>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
templ why() {
|
||||
<p>
|
||||
Cryptocurrencies were created to revolutionize the way we pay for goods
|
||||
and services, aiming to eliminate reliance on centralized entities such
|
||||
as banks and governments that control our economy.
|
||||
</p>
|
||||
<p>
|
||||
Exchanges that enforce KYC (Know Your Customer) operate similarly to traditional banks. Users are
|
||||
required to provide identification, such as a photo of their ID, to use
|
||||
these exchanges. Moreover, most of these exchanges are centralized,
|
||||
meaning that users do not own their keys. In short, this implies that
|
||||
the cryptocurrencies belong to the exchange and not the user. These
|
||||
requirements go against the decentralized and self-sovereign nature of cryptocurrencies.
|
||||
</p>
|
||||
<p>
|
||||
With KYCNOT.ME, I hope to provide people with trustworthy alternatives for buying, exchanging, trading, and
|
||||
using cryptocurrencies without having to disclose their identity, thus preserving the right to privacy.
|
||||
I want to help preserve the original ethos of cryptocurrencies.
|
||||
</p>
|
||||
}
|
||||
|
||||
templ what() {
|
||||
<p>
|
||||
<strong>KYC</strong> stands for <strong>"Know Your Customer"</strong>,
|
||||
a process designed to protect financial institutions against fraud,
|
||||
corruption, money laundering and terrorist financing. Or at least this
|
||||
is what they want you to believe.
|
||||
</p>
|
||||
<p>
|
||||
The truth is that KYC is a direct
|
||||
attack on our privacy and puts us in disadvantage against the
|
||||
governments. True criminals don't care about KYC policies. True
|
||||
criminals know perfectly how to avoid such policies. In fact, they
|
||||
normally use the FIAT system and don't even need to use
|
||||
cryptocurrencies. Banks are the biggest money launders, the
|
||||
<a
|
||||
rel="noreferrer"
|
||||
href="https://www.reuters.com/business/hsbc-fined-85-mln-anti-money-laundering-failings-2021-12-17/"
|
||||
>
|
||||
HSBC
|
||||
scandal
|
||||
</a>,
|
||||
<a rel="noreferrer" href="https://www.reuters.com/article/us-nordea-bnk-moneylaundering-idUSKCN1QL11S">Nordea</a>
|
||||
or
|
||||
<a
|
||||
rel="noreferrer"
|
||||
href="https://www.reuters.com/article/us-europe-moneylaundering-swedbank/swedbank-hit-with-record-386-million-fine-over-baltic-money-laundering-breaches-idUSKBN2163LU"
|
||||
>Swedbank</a>
|
||||
are just some examples.
|
||||
</p>
|
||||
<p>
|
||||
Chainalysis found that only 0.34% of the transaction volume with cryptocurrencies in 2023 was attributable to
|
||||
criminal
|
||||
activity. Bitcoin's share of this is significantly lower with 25%. Illicit transactions with Euros accounted
|
||||
for 1% of
|
||||
the EU's GDP or €110 billion in 2010. <a
|
||||
href="https://www.chainalysis.com/blog/2024-crypto-crime-report-introduction/"
|
||||
>[1]</a> <a
|
||||
href="https://transparency.eu/priority/financial-flows-crime/"
|
||||
>[2]</a>
|
||||
</p>
|
||||
<p>
|
||||
KYC only affects small individuals like you and me. It is an annoying
|
||||
procedure that forces us to hand our personal information to a
|
||||
third party in order to buy, use or unlock our funds. We should start
|
||||
boycotting companies that enforce such practices. We should start using
|
||||
cryptocurrencies as they were intended to be used: without barriers.
|
||||
</p>
|
||||
}
|
||||
|
||||
templ onlyBtcXmr() {
|
||||
<p>
|
||||
<strong>Bitcoin</strong>: it's the initial spark of the decentralized money.
|
||||
A solid project with a strong community. It is the most well-known and widespread cryptocurrency.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Monero</strong>: if digital cash was to exist, it should be like
|
||||
Monero. Fungible, private by design, fast and pretty low fees. Also, one
|
||||
of the oldest cryptocurrencies around with a very active community.
|
||||
</p>
|
||||
<p>
|
||||
No other currencies will be added. Most sites listed here also accept
|
||||
other cryptocurrencies, such as Ethereum or Litecoin.
|
||||
</p>
|
||||
}
|
||||
|
||||
templ listings() {
|
||||
<h3 id="request">request</h3>
|
||||
<p>
|
||||
You can request a new listing by visiting the
|
||||
<a href="/request/service">Request</a> page. The request form requires javascript to avoid spam. <a
|
||||
href="#javascript"
|
||||
>Read more about the PoW captcha in this section.</a>.
|
||||
</p>
|
||||
<h3 id="listing-process">listing process</h3>
|
||||
<p>
|
||||
The listing process is usually slow. I first need to review the service,
|
||||
read online reviews, gather evidence and history of good reviews /
|
||||
opinions, test it myself (i can't always do this), read the terms of
|
||||
service, privacy policy, etc...
|
||||
</p>
|
||||
<p>
|
||||
I do this on my own free time, so I'm slow at it. If you feel like a
|
||||
<a href="/pending">pending service</a> deserves to be listed, you can
|
||||
<a href="#contact">contact me</a> and I will try to speed up the review
|
||||
process.
|
||||
</p>
|
||||
<h3 id="attributes">what is an attribute?</h3>
|
||||
<p>
|
||||
An attribute is a feature that a service has. An attribute can be either
|
||||
good, a warning, bad or informational. Attributes are not limited, the
|
||||
list of attributes will grow if needed, you can see a full list of the
|
||||
attributes available on the Attributes page.
|
||||
</p>
|
||||
<p>
|
||||
You can click on any point to see a detailed description of what it
|
||||
means. The point page also shows all the listings that have that point.
|
||||
This is also a useful way to find listings that have a specific feature.
|
||||
</p>
|
||||
<h3 id="search">search</h3>
|
||||
<p>
|
||||
Filtering services in kycnot.me is very easy. In the main page, you will
|
||||
see 3 possible filters:
|
||||
</p>
|
||||
<div class="[&>span]:block space-y-2">
|
||||
<span>
|
||||
<b>Type filter</b>: Lets you choose between seeing all the listings
|
||||
(default), only exchanges, or only services.
|
||||
</span>
|
||||
<span>
|
||||
<b>Search bar</b>: The search bar is the most powerful filter. You can
|
||||
use it to perform a full-text search on the listings. The search will
|
||||
look for the text you enter in the name, description, keywords and
|
||||
category. The search is not case-sensitive.
|
||||
</span>
|
||||
<span>
|
||||
<b>Currency filter</b>: Lets you choose between seeing all the
|
||||
listings (default), only listings that accept a certain currency. If
|
||||
you choose more than one option, it will show all the listings that
|
||||
accept all of the selected currencies.
|
||||
</span>
|
||||
</div>
|
||||
<h3 id="levels">kyc Levels</h3>
|
||||
<p>
|
||||
KYCnot.me has a KYC level system. These levels allow you to quickly
|
||||
identify the kind of KYC practices a service may have. There are 4
|
||||
levels going from 0 to 3. The higher the level, the more invasive the
|
||||
KYC practices are.
|
||||
</p>
|
||||
<h3 id="scoring">scoring</h3>
|
||||
<p>
|
||||
Each listing has a score that is calculated based on the attributes that
|
||||
it has. The score does not reflect how good an exchange is overall, but
|
||||
it seeks to give a score in relation to its KYC practices. An exchange
|
||||
could have an awful UI/UX, but if it is very NO-KYC friendly, it will
|
||||
still get a high score.
|
||||
</p>
|
||||
<p>
|
||||
The scoring algorithm is <a
|
||||
target="_blank"
|
||||
href="https://codeberg.org/pluja/kycnot.me/src/branch/main/src/utils/score.go"
|
||||
>open source</a>,
|
||||
pull requests to improve it are welcome.
|
||||
It runs once every hour, meaning scores cannot be manually modified since they will be recalculated by the
|
||||
algorithm hourly. You can visit
|
||||
<a href="https://kycnot.me/api/v1/service/localmonero/summary">a service's score breakdown</a> to see how it is
|
||||
calculated.
|
||||
</p>
|
||||
<h3 id="order">order</h3>
|
||||
<p>
|
||||
The listings are sorted in a decreasing order by score. For listings
|
||||
that share the same score (tie), the order is random every time within
|
||||
that score range.
|
||||
</p>
|
||||
<h3 id="pending">pending</h3>
|
||||
<p>
|
||||
You can find the list of services that have been requested and are
|
||||
pending for approval here: <a href="/pending">/pending</a>
|
||||
</p>
|
||||
<h3 id="verification">verification</h3>
|
||||
<p class="mt-2">
|
||||
You will see that some services show a blue badge with a tick. This
|
||||
means that the service has been tested personally by me.
|
||||
</p>
|
||||
<p class="mt-2">
|
||||
To check the service, I make a trade on the site, or test the service
|
||||
manually. With this, I can verify that the service does not perform KYC
|
||||
practices on regular basis, and that it is not a scam, at least at the
|
||||
time of the verification.
|
||||
</p>
|
||||
<p class="mt-2">
|
||||
These checks are done randomly and without prior notice to the service.
|
||||
For this reason, and as the list is in constant growth, not all services
|
||||
have been verified yet and it takes me some time to verify them.
|
||||
</p>
|
||||
<p class="mt-2">
|
||||
A verified service does not mean that the service is safe to use
|
||||
blindly, it just means that at the time of the verification, the service
|
||||
was not performing KYC practices on regular basis, and that it was not a
|
||||
scam. It is still recommended to do your own research before using any
|
||||
service, since I can't test all the services frequently enough.
|
||||
</p>
|
||||
}
|
||||
|
||||
templ automatedTosReviews() {
|
||||
<p>
|
||||
KYCnot.me features an AI-powered tool that automatically reviews Terms of Service (ToS) for all the different
|
||||
services. It breaks down the ToS content, highlights the main points, and translates them into
|
||||
easy-to-understand language, aiming to simplify the comprehension of any service's ToS.
|
||||
</p>
|
||||
<p>
|
||||
For this, I am using OpenAI's GPT4-turbo model, which proved to be the
|
||||
most reliable and provides the best results.
|
||||
</p>
|
||||
<p>
|
||||
<b>Important note:</b> The automated tool generally delivers reliable and solid results. But it might flag false
|
||||
positives or irrelevant lines, if you find something's off, please <a href="#contact">contact me</a>.
|
||||
</p>
|
||||
}
|
||||
|
||||
templ support() {
|
||||
<p>
|
||||
If you like this project, or
|
||||
<a target="_blank" href="https://pluja.dev">any of my other projects</a>, you can support me through these
|
||||
methods:
|
||||
</p>
|
||||
<div class="[&>span]:block space-y-6">
|
||||
<!-- Monero-->
|
||||
<span>
|
||||
<span class="flex items-center space-x-2">
|
||||
<i class="icon-[tabler--coin-monero-filled]"></i>
|
||||
<span class="font-bold uppercase">Monero</span>
|
||||
</span>
|
||||
<p class="mt-1 text-xs text-white/50">
|
||||
> If your wallet supports <a rel="noreferrer" target="_blank" href="https://openalias.org/">OpenAlias</a>,
|
||||
you can use
|
||||
<span class="font-bold">kycnot.me</span> in the address field.
|
||||
</p>
|
||||
<code>{ os.Getenv("DONATION_XMR_ADDRESS") }</code>
|
||||
<details class="my-2 mt-2 rounded-lg cursor-pointer">
|
||||
<summary class="flex items-center space-x-1 text-sm text-white/60">
|
||||
<i class="icon-[tabler--qrcode]"></i>
|
||||
<span class="underline">Click for QR Code </span>
|
||||
</summary>
|
||||
<img class="my-4 size-60" src="/static/assets/xmr.webp" alt="Monero address QR code"/>
|
||||
</details>
|
||||
</span>
|
||||
<!--End Monero-->
|
||||
<hr class="border-gray-300/10"/>
|
||||
<span>
|
||||
<span class="flex items-center space-x-2">
|
||||
<i class="icon-[tabler--coin-bitcoin-filled]"></i>
|
||||
<span>
|
||||
<span class="font-bold uppercase">Bitcoin</span>
|
||||
<span>via</span>
|
||||
<a target="_blank" class="font-bold capitalize" href="https://silentpayments.xyz">
|
||||
silent
|
||||
payments
|
||||
</a>
|
||||
</span>
|
||||
</span>
|
||||
<p class="mt-1 text-xs text-white/50">
|
||||
> If you want to donate without Silent Payments, request an address via any of the <a
|
||||
href="#contact"
|
||||
>contact</a> methods.
|
||||
</p>
|
||||
<code>{ os.Getenv("DONATION_SBTC_ADDRESS") }</code>
|
||||
<details class="my-2 rounded-lg cursor-pointer">
|
||||
<summary class="flex items-center space-x-1 text-sm text-white/60">
|
||||
<i class="icon-[tabler--qrcode]"></i>
|
||||
<span class="underline">Click for QR Code </span>
|
||||
</summary>
|
||||
<img class="my-4 size-60" src="/static/assets/btcsp.webp" alt="Bitcoin Address QR Code"/>
|
||||
</details>
|
||||
</span>
|
||||
<span class="pb-4 space-y-2">
|
||||
<span class="flex items-center space-x-2">
|
||||
<i class="icon-[tabler--bolt]"></i>
|
||||
<a target="_blank" rel="noreferrer" href="https://getalby.com/p/kycnotme">Tip via Lightning Network</a>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
templ contact() {
|
||||
<p>
|
||||
If you have any queries or concerns, you can connect with me on any of the listed social media
|
||||
platforms below.
|
||||
</p>
|
||||
<p>
|
||||
For confidential communication (e2ee), please reach out via SimpleX link.
|
||||
</p>
|
||||
<div class="[&>span]:block [&>span>a]:!no-underline [&>span>a]:font-bold space-y-2">
|
||||
<span>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="https://simplex.chat/contact#/?v=2&smp=smp%3A%2F%2F0YuTwO05YJWS8rkjn9eLJDjQhFKvIYd8d4xG8X1blIU%3D%40smp8.simplex.im%2FcgKHYUYnpAIVoGb9lxb0qEMEpvYIvc1O%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAIW_JSq8wOsLKG4Xv4O54uT2D_l8MJBYKQIFj1FjZpnU%253D%26srv%3Dbeccx4yfxxbvyhqypaavemqurytl6hozr47wfc7uuecacjqdvwpw2xid.onion"
|
||||
>
|
||||
💬
|
||||
SimpleX Chat
|
||||
</a> <a class="mx-2 text-xs text-gray-400" target="_blank" href="https://simplex.chat">?</a>
|
||||
</span>
|
||||
<span>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="https://njump.me/npub188x98j0r7l2fszeph6j7hj99h8xl07n989pskk5zd69d2fcksetq5mgcqf"
|
||||
>🪶 Nostr</a> <a
|
||||
class="mx-2 text-xs text-gray-400"
|
||||
target="_blank"
|
||||
href="https://usenostr.org"
|
||||
>?</a>
|
||||
</span>
|
||||
<span>
|
||||
<a target="_blank" rel="noreferrer" href="https://fosstodon.org/@kycnotme">🦣 Mastodon</a>
|
||||
</span>
|
||||
<span>
|
||||
<a target="_blank" rel="noreferrer" href="https://x.com/kycnot">Twitter (X)</a>
|
||||
</span>
|
||||
<span>
|
||||
<a target="_blank" rel="noreferrer" href="https://lemmy.world/u/pluja">🐭 Lemmy</a>
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
templ comments() {
|
||||
<p>
|
||||
Each service has a dedicated comments section. The comments are suppored
|
||||
by a self-hosted instance of <a rel="no-referrer" target="_blank" href="https://comentario.app">Comentario</a>. An
|
||||
open-source and lightweight (20kb) commenting engine.
|
||||
</p>
|
||||
<p>
|
||||
To comment on a service's page, you can log in with Twitter, Github or Gitlab. Anonymous comments are also possible,
|
||||
but these need to be approved before being public to avoid abuse.
|
||||
</p>
|
||||
<p id="comment-moderation">
|
||||
Comments are moderated and require manual approval before being published. I approve all legitimate comments, but remove spam, scams, or low-quality submissions. Moderation may take a few days depending on when I review pending comments.
|
||||
</p>
|
||||
<p>The <a rel="no-referrer" target="_blank" href="https://gitlab.com/commento/commento">source code</a> for Comentario is licensed under MIT license.</p>
|
||||
}
|
||||
|
||||
templ transparency() {
|
||||
<p>
|
||||
In order to increase trust from visitors, KYCNOT.me strives to be as
|
||||
transparent as possible. Here are some of the ways in which I try to
|
||||
achieve this:
|
||||
</p>
|
||||
<div class="[&>span]:block space-y-2">
|
||||
<span>
|
||||
* <a href="https://codeberg.org/pluja/kycnot.me">Open Source Code</a> -
|
||||
A commit history, and full disclosure of the scoring algorithm is
|
||||
provided.
|
||||
</span>
|
||||
<span>
|
||||
* Comment section on each page, available on a self-hosted <a href="https://comentario.app">Comentario</a>
|
||||
instance.
|
||||
</span>
|
||||
<span>* All changes are recorded on the <a href="/changelog">changelog</a></span>
|
||||
<span>* See any service's score breakdown: <a href="/api/v1/service/bisq/summary">bisq example</a></span>
|
||||
<span>* Open API to get all the listings data</span>
|
||||
<span>
|
||||
* Open scoring algorithm. All services go under the same algorithm,
|
||||
meaning that the score is not subjective.
|
||||
</span>
|
||||
<span>
|
||||
* Test proofs: I am slowly adding proofs for each verified service, providing a PGP signed proof that I have
|
||||
personally tested the service. To see a proof, click the "verified" badge next to a serivce's name, inside the
|
||||
service page.
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
templ privacy() {
|
||||
<p>
|
||||
KYCNOT.me does not have trackers and never will. It does not make any
|
||||
third party connections from the frontend. No user data of any kind is
|
||||
collected. A "no-referrer" policy is enforced. Tor and I2P sites are available
|
||||
(check the footer).
|
||||
</p>
|
||||
<h3 id="javascript">javascript</h3>
|
||||
<p>
|
||||
KYCNOT.me does not require Javascript. Everything is rendered server-side.
|
||||
You can use KYCNOT.me with Javascript disabled.
|
||||
</p>
|
||||
<p>Only things that do <b>require</b> JavaScript to be enabled are:</p>
|
||||
<div class="[&>span]:block space-y-2">
|
||||
<span>
|
||||
<b>Service Requests</b>: The Proof-Of-Work captcha, that I coded myself, needs
|
||||
JavaScript for the verfication. It is an <a
|
||||
rel="no-referrer"
|
||||
target="_blank"
|
||||
href="https://codeberg.org/pluja/kycnot.me/src/branch/main/src/frontend/static/js/pow.js"
|
||||
>open-source</a>
|
||||
2.5kb javascript function.
|
||||
</span>
|
||||
<span>
|
||||
<b>Comments</b>: The comment section on each of the services, needs
|
||||
JavaScript since it needs to fetch and post to Matrix. The code that
|
||||
makes this interaction is also fully open source. Read more <a href="#comments">in this section.</a>
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
templ api() {
|
||||
<p>KYCnot.me offers a public API to get its data.</p>
|
||||
<p>
|
||||
If you make use of the API data, you should mention kycnot.me as the source
|
||||
of the data.
|
||||
</p>
|
||||
<p>
|
||||
<b>example:</b>
|
||||
<a href="/api/v1/service/bisq">/api/v1/service/bisq</a>
|
||||
</p>
|
||||
<p>
|
||||
<b>example 2:</b>
|
||||
<a href="/api/v1/service/bisq.network">/api/v1/service/bisq.network</a>
|
||||
</p>
|
||||
<p>
|
||||
<b>rate limit:</b>
|
||||
5req/min (with bursts of 5)
|
||||
</p>
|
||||
}
|
||||
|
||||
templ disclaimer() {
|
||||
<p>
|
||||
This website does not provide any financial advice. Always do your
|
||||
own research before using any service. This site is for informational
|
||||
purposes only. I'm not responsible for any loss of funds or any other
|
||||
damage that may occur by using any of the services listed here. Use at
|
||||
your own risk.
|
||||
</p>
|
||||
}
|
||||
|
||||
templ inlineCss() {
|
||||
<style>
|
||||
article p {
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
article a {
|
||||
color: rgb(163 230 53);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.2rem;
|
||||
}
|
||||
|
||||
article div {
|
||||
padding-top: .5em;
|
||||
padding-bottom: .5em;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 0.3rem;
|
||||
font-weight: bold;
|
||||
font-family: samo;
|
||||
color: rgb(163 230 53);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 1.1em;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
h3::before {
|
||||
content: "~ ";
|
||||
}
|
||||
|
||||
article blockquote {
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-left: 1rem;
|
||||
border-left: 0.3rem solid rgb(163 230 53);
|
||||
color: rgb(142, 146, 150);
|
||||
}
|
||||
|
||||
code {
|
||||
background: #2b282872;
|
||||
border: 1px solid #494242;
|
||||
border-radius: 0.2rem;
|
||||
font-weight: bold;
|
||||
border-left: 3px solid #89f333;
|
||||
color: #d3cccc;
|
||||
font-family: samo;
|
||||
max-width: 100%;
|
||||
overflow: scorll;
|
||||
padding: 1em 1em;
|
||||
display: block;
|
||||
word-wrap: break-word;
|
||||
max-width: 90vw;
|
||||
margin-top: .2em;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
<section class="pt-14">
|
||||
<div class="flex flex-col justify-center items-center space-x-4">
|
||||
<!--<h1 class="text-2xl font-bold capitalize-first">{{.Attribute.Title}}</h1>-->
|
||||
<!-- Description -->
|
||||
<div class="p-4 m-4 {{if eq "info" .Attribute.Rating}} border rounded-lg border-blue-600/40 bg-blue-600/20
|
||||
{{end}} {{if eq "good" .Attribute.Rating}} border rounded-lg border-green-600/40 bg-green-600/20 {{end}}
|
||||
{{if eq "warn" .Attribute.Rating}} border rounded-lg border-yellow-600/40 bg-yellow-600/20 {{end}} {{if
|
||||
eq "bad" .Attribute.Rating}} border rounded-lg border-red-600/40 bg-red-600/20 {{end}} ">
|
||||
|
||||
<h3 class="mb-3 text-lg font-bold uppercase border-b md:text-xl border-b-white/20">
|
||||
{{if eq "info" .Attribute.Rating}}
|
||||
🔵
|
||||
{{end}}
|
||||
{{if eq "good" .Attribute.Rating}}
|
||||
✅
|
||||
{{end}}
|
||||
{{if eq "warn" .Attribute.Rating}}
|
||||
⚠️
|
||||
{{end}}
|
||||
{{if eq "bad" .Attribute.Rating}}
|
||||
🛑
|
||||
{{end}}
|
||||
{{.Attribute.Title}}
|
||||
</h3>
|
||||
|
||||
<p class="max-w-lg">
|
||||
{{if ne .Attribute.Description ""}}
|
||||
{{.Attribute.Description | safe}}
|
||||
{{else}}
|
||||
{{.Attribute.Name}} does not have a description.
|
||||
{{end}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Services list -->
|
||||
<section class="flex flex-col justify-center items-center px-1 mx-2 mt-6">
|
||||
<h2 class="text-lg font-bold text-center uppercase">Services with this point:</h2>
|
||||
<div class="grid grid-cols-1 gap-3 mx-auto mt-2 max-w-6xl md:grid-cols-2 lg:grid-cols-3">
|
||||
{{range .Services}}
|
||||
{{partial "partials/service_card" .}}
|
||||
{{end}}
|
||||
</div>
|
||||
</section>
|
52
src/frontend/templates/attribute.templ
Normal file
@ -0,0 +1,52 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"kycnot.me/frontend/templates/partials"
|
||||
"kycnot.me/internal/ent"
|
||||
"kycnot.me/internal/ent/attribute"
|
||||
)
|
||||
|
||||
templ Attribute(attr *ent.Attribute) {
|
||||
@Base(attr.Title) {
|
||||
<section class="pt-14">
|
||||
<div class="flex flex-col justify-center items-center space-x-4">
|
||||
<div
|
||||
class={
|
||||
"p-4 m-4 border rounded-lg",
|
||||
templ.KV("border-blue-600/40 bg-blue-600/20", attr.Rating == attribute.RatingInfo),
|
||||
templ.KV("border-green-600/40 bg-green-600/20", attr.Rating == attribute.RatingGood),
|
||||
templ.KV("border-yellow-600/40 bg-yellow-600/20", attr.Rating == attribute.RatingWarn),
|
||||
templ.KV("border-red-600/40 bg-red-600/20", attr.Rating == attribute.RatingBad),
|
||||
}
|
||||
>
|
||||
<h3 class="mb-3 text-lg font-bold uppercase border-b md:text-xl border-b-white/20">
|
||||
<i
|
||||
class={
|
||||
"text-lg",
|
||||
templ.KV("text-blue-500 icon-[tabler--info-circle-filled]", attr.Rating == attribute.RatingInfo),
|
||||
templ.KV("text-green-500 icon-[tabler--circle-check-filled]", attr.Rating == attribute.RatingGood),
|
||||
templ.KV("text-yellow-500 icon-[tabler--alert-triangle-filled]", attr.Rating == attribute.RatingWarn),
|
||||
templ.KV("text-red-500 icon-[tabler--alert-triangle-filled]", attr.Rating == attribute.RatingBad),
|
||||
}
|
||||
></i>
|
||||
{ attr.Title }
|
||||
</h3>
|
||||
if attr.Description != "" {
|
||||
<p class="max-w-lg">
|
||||
@templ.Raw(attr.Description)
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Services list -->
|
||||
<section class="flex flex-col justify-center items-center px-1 mx-2 mt-12">
|
||||
<h2 class="mb-3 text-lg font-bold text-center uppercase">Also have this attribute:</h2>
|
||||
<div class="grid grid-cols-1 gap-3 mx-auto mt-2 max-w-6xl md:grid-cols-2 lg:grid-cols-3">
|
||||
for _, s := range attr.Edges.Services {
|
||||
@partials.ServiceCard(s)
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
}
|
33
src/frontend/templates/attributes_list.templ
Normal file
@ -0,0 +1,33 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"kycnot.me/frontend/templates/partials"
|
||||
"kycnot.me/internal/ent"
|
||||
)
|
||||
|
||||
templ AttributeList(attributes []*ent.Attribute) {
|
||||
@Base("Attributes") {
|
||||
<section class="flex flex-col items-center w-full">
|
||||
<header class="my-4 text-center">
|
||||
<h2 class="text-xl">Service Attributes</h2>
|
||||
<p class="mt-0.5 text-xs text-white/40">Click any attribute to see a detail</p>
|
||||
</header>
|
||||
<div class="mt-3 text-center text-gray-500">
|
||||
<a href="/">
|
||||
<span class="p-1 text-xs transition duration-200 hover:text-gray-400">All</span>
|
||||
</a>
|
||||
<a href="/?t=exchange">
|
||||
<span class="p-1 text-xs transition duration-200 hover:text-gray-400">Exchanges</span>
|
||||
</a>
|
||||
<a href="/?t=service">
|
||||
<span class="p-1 text-xs transition duration-200 hover:text-gray-400">Services</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="mt-6 space-y-2 w-full max-w-lg">
|
||||
for _, attribute := range attributes {
|
||||
@partials.AttributeLine(attribute)
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
}
|
115
src/frontend/templates/base.templ
Normal file
@ -0,0 +1,115 @@
|
||||
package templates
|
||||
|
||||
func buildTitle(part string) string {
|
||||
if part != "" {
|
||||
return part + " | KYCNOT.ME"
|
||||
}
|
||||
|
||||
return "KYCNOT.ME"
|
||||
}
|
||||
|
||||
templ Base(title string) {
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta
|
||||
name="description"
|
||||
content="Find the best NON-KYC exchanges and services to use and spend your crypto anonymously."
|
||||
/>
|
||||
<meta
|
||||
name="keywords"
|
||||
content="KYC, AML, Bitcoin, Crypto, Cryptocurrency, Exchange, Exchanges, Service, Services, Anonymous, Anonymity, Privacy, Pseudonymity, Pseudonymous, Non-KYC, No-KYC, No KYC, Monero, XMR, BTC"
|
||||
/>
|
||||
<meta property="og:title" content={ buildTitle(title) }/>
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Find the best NON-KYC exchanges and services to use and spend your crypto anonymously."
|
||||
/>
|
||||
<meta property="og:type" content="website"/>
|
||||
<meta
|
||||
http-equiv="onion-location"
|
||||
content="http://kycnotmezdiftahfmc34pqbpicxlnx3jbf5p7jypge7gdvduu7i6qjqd.onion/"
|
||||
/>
|
||||
<meta property="og:image" content="https://kycnot.me/static/assets/banner.webp"/>
|
||||
<meta property="thumbnail" content="https://kycnot.me/static/assets/banner.webp"/>
|
||||
<meta name="twitter:image" content="https://kycnot.me/static/assets/banner.webp"/>
|
||||
<meta property="og:url" content="https://kycnot.me"/>
|
||||
<!-- Mastodon Verification -->
|
||||
<link rel="me" href="https://fosstodon.org/@kycnotme"/>
|
||||
<!-- CSS -->
|
||||
<link rel="stylesheet" href="/static/css/balloon.min.css"/>
|
||||
<!-- Site Config -->
|
||||
<title>{ buildTitle(title) }</title>
|
||||
<link rel="stylesheet" href="/static/css/style.css"/>
|
||||
<link rel="shortcut icon" href="/static/assets/favicon.webp" type="image/x-icon"/>
|
||||
</head>
|
||||
<style>
|
||||
.capitalize-first::first-letter {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
</style>
|
||||
<body class="h-full text-gray-200 bg-fixed bg-black bg-center bg-cover font-samo" style="background-image: url('/static/assets/gradient.svg');">
|
||||
<!-- Nav Bar -->
|
||||
<nav class="flex justify-center items-center w-full bg-none">
|
||||
<div class="flex flex-col justify-between items-center px-4 w-full max-w-6xl md:flex-row">
|
||||
<!-- Logo -->
|
||||
<a href="/">
|
||||
<img src="/static/assets/logo_wide.svg" alt="Logo" class="pt-2 max-w-48 lg:max-w-48"/>
|
||||
</a>
|
||||
<!-- Primary Navbar items -->
|
||||
<div class="[&>a]:inline [&>a]:text-xs">
|
||||
<a href="/" class="px-1 py-1 text-gray-500 transition duration-300 hover:text-lime-500 md:text-base">
|
||||
Home
|
||||
</a>
|
||||
<a
|
||||
href="/request"
|
||||
class="px-1 py-1 text-gray-500 transition duration-300 hover:text-lime-500 md:text-base"
|
||||
>
|
||||
Request
|
||||
</a>
|
||||
<a
|
||||
href="/about"
|
||||
class="px-1 py-1 text-gray-500 transition duration-300 hover:text-lime-500 md:text-base"
|
||||
>
|
||||
About
|
||||
</a>
|
||||
<a
|
||||
href="/about#support"
|
||||
class="px-1 py-1 text-gray-500 transition duration-300 md:text-base hover:text-lime-500"
|
||||
>
|
||||
Support
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<!---->
|
||||
{ children... }
|
||||
<footer class="my-6 space-x-4 text-md text-center *:text-lime-600">
|
||||
<a
|
||||
class="hover:text-lime-300"
|
||||
href="https://nostr.com/npub188x98j0r7l2fszeph6j7hj99h8xl07n989pskk5zd69d2fcksetq5mgcqf"
|
||||
>nostr</a>
|
||||
<a class="hover:text-lime-300" href="https://fosstodon.org/@kycnotme">mastodon</a>
|
||||
<a
|
||||
class="hover:text-lime-300"
|
||||
href="http://kycnotmezdiftahfmc34pqbpicxlnx3jbf5p7jypge7gdvduu7i6qjqd.onion/"
|
||||
>tor</a>
|
||||
<a
|
||||
class="hover:text-lime-300"
|
||||
href="http://nti3rj4j4disjcm2kvp4eno7otcejbbxv3ggxwr5tpfk4jucah7q.b32.i2p"
|
||||
>i2p</a>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
<style>
|
||||
.gradient {
|
||||
background: rgb(5, 58, 24);
|
||||
background: linear-gradient(153deg,
|
||||
rgb(3, 53, 21) 0%,
|
||||
rgb(0, 17, 4) 20%,
|
||||
rgba(0, 0, 0, 1) 100%);
|
||||
}
|
||||
</style>
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
<section class="container px-4 py-12 mx-auto">
|
||||
<h1 class="mb-10 text-3xl font-bold text-center text-white/80">Changelog</h1>
|
||||
|
||||
<div class="space-y-4">
|
||||
{{ range .Changes }}
|
||||
<div class="overflow-hidden border rounded-md border-white/20">
|
||||
<div class="p-4">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="text-base font-semibold text-white/80">{{.Title}}</h3>
|
||||
<span class="text-xs text-white/40">{{.Created}}</span>
|
||||
</div>
|
||||
<p class="mb-4 text-sm text-white/70">{{.Summary | safe}}</p>
|
||||
|
||||
{{ if .Expand.service }}
|
||||
<div class="pt-2 mt-1 border-t border-white/10">
|
||||
{{ with .Expand.service }}
|
||||
<span class="text-sm text-white/50">
|
||||
Related service: <a class="underline transition-colors duration-200 text-lime-700 hover:text-blue-300"
|
||||
href="/service/{{.Name}}">{{ .Name }}</a>
|
||||
</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</section>
|
44
src/frontend/templates/changelog.templ
Normal file
@ -0,0 +1,44 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kycnot.me/internal/ent"
|
||||
)
|
||||
|
||||
func changeTitle(change *ent.Change) string {
|
||||
if _, err := change.Edges.ServiceOrErr(); err != nil {
|
||||
return change.Title
|
||||
}
|
||||
|
||||
// If the service is not found, use the default title format.
|
||||
return fmt.Sprintf("%s: %s", change.Edges.Service.Name, change.Title)
|
||||
}
|
||||
|
||||
templ Changelog(changes []*ent.Change) {
|
||||
@Base("Changelog") {
|
||||
<div class="flex flex-col items-center">
|
||||
<h1 class="my-4 text-xl font-bold">Changelog</h1>
|
||||
if len(changes) == 0 {
|
||||
<div class="mt-4 text-center">No changes found.</div>
|
||||
} else {
|
||||
for _, change := range changes {
|
||||
<div
|
||||
class={
|
||||
"p-2 mt-4 w-full max-w-lg border", templ.KV("border-orange-500/40 bg-orange-500/10", change.Warning),
|
||||
templ.KV("border-blue-600/40 bg-blue-600/10", change.Warning == false),
|
||||
}
|
||||
>
|
||||
<h3 class="text-xs text-white/50">
|
||||
{ change.CreatedAt.Format("January 2, 2006 - 15:04") } {
|
||||
change.CreatedAt.Location().String() }
|
||||
</h3>
|
||||
<h2 class="font-bold uppercase">{ changeTitle(change) }</h2>
|
||||
<p class="mt-1 text-sm font-normal text-white/80">
|
||||
@templ.Raw(change.Summary)
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
{{if .Announcement}}
|
||||
<a target="_blank" href="{{.Announcement.Link}}"
|
||||
class="flex flex-col justify-center items-center p-2 mx-auto mt-4 space-x-2 max-w-xs rounded-lg border transition duration-200 {{if .Announcement.Warning}}border-yellow-900 hover:border-yellow-700{{else}} hover:border-lime-700 border-lime-900{{end}} bg-black/30">
|
||||
<span class="flex justify-center items-center font-bold">
|
||||
{{if .Announcement.Warning}}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="mr-1.5 text-yellow-600 size-5" width="24" height="24" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M12 1.67c.955 0 1.845 .467 2.39 1.247l.105 .16l8.114 13.548a2.914 2.914 0 0 1 -2.307 4.363l-.195 .008h-16.225a2.914 2.914 0 0 1 -2.582 -4.2l.099 -.185l8.11 -13.538a2.914 2.914 0 0 1 2.491 -1.403zm.01 13.33l-.127 .007a1 1 0 0 0 0 1.986l.117 .007l.127 -.007a1 1 0 0 0 0 -1.986l-.117 -.007zm-.01 -7a1 1 0 0 0 -.993 .883l-.007 .117v4l.007 .117a1 1 0 0 0 1.986 0l.007 -.117v-4l-.007 -.117a1 1 0 0 0 -.993 -.883z"
|
||||
stroke-width="0" fill="currentColor" />
|
||||
</svg>
|
||||
{{else}}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="mr-1.5 text-lime-600 size-5" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<circle cx="12" cy="12" r="9" />
|
||||
<line x1="12" y1="8" x2="12.01" y2="8" />
|
||||
<polyline points="11 12 12 12 12 16 13 16" />
|
||||
</svg>
|
||||
{{end}}
|
||||
{{.Announcement.Title}}
|
||||
</span>
|
||||
<span class="text-xs lowercase">{{.Announcement.Body}}</span>
|
||||
</a>
|
||||
{{end}}
|
||||
|
||||
|
||||
<main class="py-4 text-lime-500">
|
||||
<div class="px-4 pt-2">
|
||||
<div class="mb-2 text-center bg-transparent md:grid">
|
||||
<p class="font-mono text-sm font-bold uppercase md:text-base">{{.RandomPitch}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- End Filters -->
|
||||
<form action="/">
|
||||
<input type="hidden" name="t" id="t" value="{{.Filters.Type}}" />
|
||||
<div class="flex justify-center items-center mt-4">
|
||||
<input
|
||||
class="text-xs text-lime-500 bg-transparent rounded-lg border border-lime-500/60 placeholder-white/30"
|
||||
placeholder="Search anything..." value="{{.Filters.Query}}" type="text" name="q" id="q">
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center items-center pt-2.5 space-x-2">
|
||||
<span class="flex flex-col justify-center items-center">
|
||||
<label class="text-xs uppercase" for="btc">btc</label>
|
||||
<input
|
||||
class="text-lime-500 bg-transparent rounded-full appearance-none outline-none focus:ring-0 border-lime-500/60"
|
||||
type="checkbox" {{if eq "on" .Filters.Btc}}checked{{end}} name="btc" id="btc">
|
||||
</span>
|
||||
<span class="flex flex-col justify-center items-center">
|
||||
<label class="text-xs uppercase" for="xmr">xmr</label>
|
||||
<input
|
||||
class="text-lime-500 bg-transparent rounded-full appearance-none outline-none focus:ring-0 border-lime-500/60"
|
||||
type="checkbox" {{if eq "on" .Filters.Xmr}}checked{{end}} name="xmr" id="xmr">
|
||||
</span>
|
||||
<span class="flex flex-col justify-center items-center">
|
||||
<label class="text-xs uppercase" for="ln">ln</label>
|
||||
<input
|
||||
class="text-lime-500 bg-transparent rounded-full appearance-none outline-none focus:ring-0 border-lime-500/60"
|
||||
type="checkbox" {{if eq "on" .Filters.Ln}}checked{{end}} name="ln" id="ln">
|
||||
</span>
|
||||
<span class="flex flex-col justify-center items-center">
|
||||
<label class="text-xs uppercase" for="fiat">fiat</label>
|
||||
<input
|
||||
class="text-lime-500 bg-transparent rounded-full appearance-none outline-none focus:ring-0 border-lime-500/60"
|
||||
type="checkbox" {{if eq "on" .Filters.Fiat}}checked{{end}} name="fiat" id="fiat">
|
||||
</span>
|
||||
<span class="flex flex-col justify-center items-center">
|
||||
<label class="text-xs uppercase" for="cash">cash</label>
|
||||
<input
|
||||
class="text-lime-500 bg-transparent rounded-full appearance-none outline-none focus:ring-0 border-lime-500/60"
|
||||
type="checkbox" {{if eq "on" .Filters.Cash}}checked{{end}} name="cash" id="cash">
|
||||
</span>
|
||||
<button class="p-1 text-xs font-bold uppercase bg-none rounded-lg border border-lime-500/60"
|
||||
type="submit">filter</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="mt-3 text-center text-gray-500">
|
||||
<a href="/">
|
||||
<span
|
||||
class="p-1 {{if eq "" .Filters.Type}}border-b border-lime-500/60 text-lime-500{{end}} text-xs">All</span>
|
||||
</a>
|
||||
<a href="/?t=exchange">
|
||||
<span class="p-1 {{if eq "exchange" .Filters.Type}}border-b border-lime-500/60 text-lime-500{{end}}
|
||||
text-xs">Exchanges</span>
|
||||
</a>
|
||||
<a href="/?t=service">
|
||||
<span class="p-1 {{if eq "service" .Filters.Type}}border-b border-lime-500/60 text-lime-500{{end}}
|
||||
text-xs">Services</span>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Filters -->
|
||||
</main>
|
||||
|
||||
<!-- Services list -->
|
||||
<section class="flex justify-center items-center px-3 pb-12 mt-4">
|
||||
<div class="grid grid-cols-1 gap-3 max-w-6xl lg:grid-cols-3">
|
||||
{{range .Services}}
|
||||
{{partial "partials/service_card" .}}
|
||||
{{end}}
|
||||
</div>
|
||||
</section>
|
115
src/frontend/templates/index.templ
Normal file
@ -0,0 +1,115 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"kycnot.me/frontend/templates/partials"
|
||||
"kycnot.me/internal/ent"
|
||||
"kycnot.me/internal/models"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
func getRandomPitch() string {
|
||||
pitches := []string{
|
||||
"KYC-Free Crypto Freedom.",
|
||||
"Goodbye KYC, hello privacy.",
|
||||
"KYC is a scam. Don't fall for it.",
|
||||
"Trade anonymously, live freely.",
|
||||
"KYC-free zone ahead.",
|
||||
"Privacy is not a crime.",
|
||||
"No ID? No problem.",
|
||||
"True financial independence.",
|
||||
}
|
||||
return pitches[rand.Intn(len(pitches))]
|
||||
}
|
||||
|
||||
func getAnnouncementStyle(warning bool) string {
|
||||
if warning {
|
||||
return "border-yellow-900 hover:border-yellow-700"
|
||||
}
|
||||
return "hover:border-lime-700 border-lime-900"
|
||||
}
|
||||
|
||||
templ Index(ann *ent.Announcement, services []*ent.Service, filters models.ServiceFilters) {
|
||||
@Base("") {
|
||||
if ann != nil {
|
||||
<a target="_blank" href={ templ.URL(ann.Link) } class={ getAnnouncementStyle(ann.Warning) + " flex flex-col justify-center items-center p-2 mx-auto mt-4 space-x-2 max-w-xs rounded-lg border transition duration-200 bg-black/30" }>
|
||||
<span class="flex justify-center items-center font-bold">
|
||||
if ann.Warning {
|
||||
<i class="icon-[tabler--alert-triangle-filled] mr-1.5 text-yellow-600"></i>
|
||||
} else {
|
||||
<i class="ti icon-[tabler--news] mr-1.5 text-lime-600"></i>
|
||||
}
|
||||
{ ann.Title }
|
||||
</span>
|
||||
<span class="text-xs lowercase">{ ann.Body }</span>
|
||||
</a>
|
||||
}
|
||||
<main class="pt-4 pb-1 text-lime-500">
|
||||
<div class="px-4 pt-2">
|
||||
<div class="mb-2 text-center bg-transparent md:grid">
|
||||
<p class="font-mono text-sm font-bold uppercase md:text-base">{ getRandomPitch() }</p>
|
||||
</div>
|
||||
</div>
|
||||
// Filters
|
||||
<form action="/" method="get">
|
||||
<input type="hidden" name="t" id="t" value={ filters.Type }/>
|
||||
// Search query
|
||||
<div class="flex justify-center items-center mt-4">
|
||||
<input
|
||||
class="text-xs text-lime-500 bg-transparent rounded-lg border border-lime-500/60 placeholder-white/30"
|
||||
placeholder="Search anything..."
|
||||
value={ filters.Query }
|
||||
type="text"
|
||||
name="q"
|
||||
id="q"
|
||||
/>
|
||||
</div>
|
||||
// Currency checkboxes
|
||||
<div class="flex justify-center items-center pt-2.5 space-x-2">
|
||||
{{ currencies := []string{"xmr", "btc", "ln", "fiat", "cash"} }}
|
||||
for _, currency := range currencies {
|
||||
<span class="flex flex-col justify-center items-center">
|
||||
<label class="text-xs uppercase" for={ currency }>{ currency }</label>
|
||||
if val, ok := filters.Currencies[currency]; ok {
|
||||
<input
|
||||
class="text-lime-500 bg-transparent rounded-full appearance-none outline-none focus:ring-0 border-lime-500/60"
|
||||
type="checkbox"
|
||||
checked?={ val }
|
||||
name={ currency }
|
||||
id={ currency }
|
||||
/>
|
||||
} else {
|
||||
<input
|
||||
class="text-lime-500 bg-transparent rounded-full appearance-none outline-none focus:ring-0 border-lime-500/60"
|
||||
type="checkbox"
|
||||
name={ currency }
|
||||
id={ currency }
|
||||
/>
|
||||
}
|
||||
</span>
|
||||
}
|
||||
<button class="p-1 text-xs font-bold text-lime-500 uppercase bg-none rounded-lg border transition duration-200 border-lime-500/60 hover:border-lime-500 hover:text-lime-400" type="submit">filter</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mt-3 text-center text-gray-500">
|
||||
<a href="/">
|
||||
<span class={ "p-1 text-xs transition duration-200 hover:text-gray-400", templ.KV("underline", filters.Type == "") }>All</span>
|
||||
</a>
|
||||
<a href="/?t=exchange">
|
||||
<span class={ "p-1 text-xs transition duration-200 hover:text-gray-400", templ.KV("underline", filters.Type == "exchange") }>Exchanges</span>
|
||||
</a>
|
||||
<a href="/?t=service">
|
||||
<span class={ "p-1 text-xs transition duration-200 hover:text-gray-400", templ.KV("underline", filters.Type == "service") }>Services</span>
|
||||
</a>
|
||||
</div>
|
||||
// End Filters
|
||||
</main>
|
||||
// Services List
|
||||
<section class="flex justify-center items-center px-3 pb-12 mt-4">
|
||||
<div class="grid grid-cols-1 gap-3 max-w-6xl lg:grid-cols-3">
|
||||
for _, service := range services {
|
||||
@partials.ServiceCard(service)
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang='en' data-theme="dark">
|
||||
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Find the best NON-KYC exchanges and services to use and spend your crypto anonymously.">
|
||||
<meta name="keywords"
|
||||
content="KYC, AML, Bitcoin, Crypto, Cryptocurrency, Exchange, Exchanges, Service, Services, Anonymous, Anonymity, Privacy, Pseudonymity, Pseudonymous, Non-KYC, No-KYC, No KYC, Monero, XMR, BTC">
|
||||
<meta property="og:title" content="{{.Title}}" />
|
||||
<meta property="og:description"
|
||||
content="Find the best NON-KYC exchanges and services to use and spend your crypto anonymously." />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta http-equiv="onion-location" content="http://kycnotmezdiftahfmc34pqbpicxlnx3jbf5p7jypge7gdvduu7i6qjqd.onion/" />
|
||||
<meta property="og:image" content="https://kycnot.me/static/assets/banner.webp" />
|
||||
<meta property="thumbnail" content="https://kycnot.me/static/assets/banner.webp">
|
||||
<meta name="twitter:image" content="https://kycnot.me/static/assets/banner.webp">
|
||||
<meta property="og:url" content="https://kycnot.me" />
|
||||
|
||||
<!-- Mastodon Verification -->
|
||||
<link rel="me" href="https://fosstodon.org/@kycnotme">
|
||||
|
||||
<!-- CSS -->
|
||||
<link rel="stylesheet" href="/static/css/balloon.min.css">
|
||||
|
||||
<!-- Site Config -->
|
||||
<title>{{.Title}}</title>
|
||||
<link rel='stylesheet' href='/static/css/style.css'>
|
||||
<link rel="shortcut icon" href="/static/assets/favicon.webp" type="image/x-icon">
|
||||
</head>
|
||||
|
||||
<style>
|
||||
.capitalize-first::first-letter {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="h-full text-gray-200 bg-fixed bg-black bg-center bg-cover font-samo" style="background-image: url('/static/assets/gradient.webp');">
|
||||
<!-- Nav Bar -->
|
||||
<nav class="flex items-center justify-center w-full bg-none">
|
||||
<div class="flex flex-col items-center justify-between w-full max-w-6xl px-4 md:flex-row">
|
||||
<!-- Logo -->
|
||||
<a href="/">
|
||||
<img src="/static/assets/logo_wide.svg" alt="Logo" class="pt-2 max-w-48 lg:max-w-48" />
|
||||
</a>
|
||||
|
||||
<!-- Primary Navbar items -->
|
||||
<div class="[&>a]:inline [&>a]:text-xs">
|
||||
<a
|
||||
href="/"
|
||||
class="px-1 py-1 font-semibold md:text-base {{if or (eq .Current "index") (eq .Current "")}} text-lime-500 border-lime-500 border-b-2 {{ else }} text-gray-500 hover:text-lime-500 {{ end }}"
|
||||
>
|
||||
Home
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/request/service"
|
||||
class="px-1 py-1 text-gray-500 transition duration-300 md:text-base {{if or (eq .Current "request") (eq .Current "")}} text-lime-500 border-lime-500 border-b-2 {{ else }} text-gray-500 hover:text-lime-500 {{ end }}"
|
||||
>
|
||||
Request
|
||||
</a>
|
||||
<a
|
||||
href="/about"
|
||||
class="px-1 py-1 text-gray-500 transition duration-300 md:text-base {{if or (eq .Current "about") (eq .Current "")}} text-lime-500 border-lime-500 border-b-2 {{ else }} text-gray-500 hover:text-lime-500 {{ end }}"
|
||||
>
|
||||
About
|
||||
</a>
|
||||
<a
|
||||
href="/about#support"
|
||||
class="px-1 py-1 text-gray-500 transition duration-300 md:text-base hover:text-lime-500"
|
||||
>
|
||||
Support
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{{if .Error}}
|
||||
<div class="flex items-center justify-center">
|
||||
<p class="px-2 py-2 font-bold text-center rounded-lg bg-red-500/70 text-md text-neutral-100">
|
||||
{{ .Error }}
|
||||
</p>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if .Message}}
|
||||
<div class="flex items-center justify-center">
|
||||
<p class="px-2 py-2 font-bold text-center rounded-lg text-md bg-blue-500/70 text-neutral-100">
|
||||
{{ .Message }}
|
||||
</p>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<!---->
|
||||
|
||||
{{ template "content" . }}
|
||||
|
||||
<footer class="my-6 space-x-4 text-md text-center *:text-lime-600">
|
||||
<a class="hover:text-lime-300" href="https://nostr.com/npub188x98j0r7l2fszeph6j7hj99h8xl07n989pskk5zd69d2fcksetq5mgcqf">nostr</a>
|
||||
<a class="hover:text-lime-300" href="https://fosstodon.org/@kycnotme">mastodon</a>
|
||||
<a class="hover:text-lime-300" href="http://kycnotmezdiftahfmc34pqbpicxlnx3jbf5p7jypge7gdvduu7i6qjqd.onion/">tor</a>
|
||||
<!-- <a class="hover:text-lime-300" href="http://kycnot3724gujekedbe6pwoejfbnggdv26losox25iaokev5ctaq.b32.i2p/">i2p</a> -->
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
<style>
|
||||
.gradient {
|
||||
background: rgb(5, 58, 24);
|
||||
background: linear-gradient(153deg,
|
||||
rgb(3, 53, 21) 0%,
|
||||
rgb(0, 17, 4) 20%,
|
||||
rgba(0, 0, 0, 1) 100%);
|
||||
}
|
||||
</style>
|
@ -1,217 +0,0 @@
|
||||
<style>
|
||||
article {
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
article p {
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
article a {
|
||||
color: rgb(163 230 53);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.2rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 0.3rem;
|
||||
font-weight: bold;
|
||||
font-family: samo;
|
||||
color: rgb(163 230 53);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 1.1em;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
h3::before {
|
||||
content: "~ ";
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-top: 0.3rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-left: 1rem;
|
||||
list-style: square;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 0.15rem;
|
||||
}
|
||||
|
||||
article a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
article blockquote {
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-left: 1rem;
|
||||
border-left: 0.3rem solid rgb(163 230 53);
|
||||
color: rgb(142, 146, 150);
|
||||
}
|
||||
|
||||
code {
|
||||
background: #2b282872;
|
||||
border: 1px solid #494242;
|
||||
border-radius: 0.2rem;
|
||||
font-weight: bold;
|
||||
border-left: 3px solid #89f333;
|
||||
color: #d3cccc;
|
||||
font-family: samo;
|
||||
max-width: 100%;
|
||||
overflow: scorll;
|
||||
padding: 1em 1em;
|
||||
display: block;
|
||||
word-wrap: break-word;
|
||||
max-width: 90vw;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="main" class="flex flex-col justify-center items-center my-8">
|
||||
<article class="md:p-4 md:max-w-5xl font-inter">
|
||||
<div class="px-4 py-2 m-2 rounded-xl bg-gray-500/10">
|
||||
<h2 id="why" class="font-bold text-lime-400">
|
||||
nostr?
|
||||
</h2>
|
||||
<p>
|
||||
Start by reading
|
||||
<a target="_blank" href="https://usenostr.org" target="_blank"
|
||||
>the nostr basics</a
|
||||
>
|
||||
to understand how Nostr works.
|
||||
</p>
|
||||
|
||||
<h3 id="creating an account" class="pt-4 w-full border-t border-white/20">
|
||||
creating an account
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
Creating a Nostr account is as easy as generating a private key. From
|
||||
the private key, your public key will be derived. The public key acts as
|
||||
your <b>username</b>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this guide, we will use
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://github.com/nostr-protocol/nips/blob/master/07.md"
|
||||
>Browser Signer Extensions</a
|
||||
>
|
||||
to generate the private key, these act as a vault for your private key,
|
||||
and Nostr apps will interact with the extension, issuing sign requests.
|
||||
This way, your private key never leaves your computer local storage.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For this, I recommend you use
|
||||
<a target="_blank" href="https://github.com/reyamir/nostr-connect"
|
||||
>Nostr Connect</a
|
||||
>
|
||||
extension. Install it on
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://chromewebstore.google.com/detail/nostr-connect/ampjiinddmggbhpebhaegmjkbbeofoaj"
|
||||
>Chrome</a
|
||||
>
|
||||
or
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://addons.mozilla.org/en-US/firefox/addon/nostr-connect/"
|
||||
>Firefox</a
|
||||
>. You can also find a list of available Signers
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://github.com/aljazceru/awesome-nostr#nip-07-browser-extensions"
|
||||
>here</a
|
||||
>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Then, open the extension, generate a private key and click save. That's
|
||||
all, you are now part of Nostr.
|
||||
</p>
|
||||
|
||||
<p>Other ways to generate a key:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Use key mining tools like
|
||||
<a target="_blank" href="https://github.com/grunch/rana">rana</a>.
|
||||
</li>
|
||||
<li>
|
||||
Use
|
||||
<a target="_blank" href="https://github.com/fiatjaf/noscl"
|
||||
>nostr CLI</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
Use platforms like
|
||||
<a target="_blank" href="https://primal.net">primal</a>,
|
||||
<a target="_blank" href="https://snort.social/">snort</a> or
|
||||
<a target="_blank" href="https://coracle.social/">coracle</a>.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3
|
||||
id="configure your profile"
|
||||
class="pt-4 w-full border-t border-white/20"
|
||||
>
|
||||
configure your profile
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
Visit
|
||||
<a target="_blank" href="https://metadata.nostr.com/"
|
||||
>Nostr Profile Manager</a
|
||||
>
|
||||
and configure your profile:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Configure the Metadata fields.</li>
|
||||
<li>
|
||||
Add some relays. Check out
|
||||
<a target="_blank" href="https://nostr.watch">nostr.watch</a> for a
|
||||
list of relays.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="use" class="pt-4 w-full border-t border-white/20">
|
||||
use
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
After your account is set up, you will be able to log in to any platform
|
||||
that uses the Nostr protocol, and use it. Take a look <a target="_blank" href="https://nostr.net/">here</a> to find a client that suites your needs.
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
@ -1,39 +0,0 @@
|
||||
<a href="/attr/{{.ID}}" class="block py-1.5 px-3 text-center text-sm border rounded-lg transition duration-300
|
||||
{{if eq "good" .Rating }}border-green-900 bg-green-900/30 hover:bg-green-900/50 hover:border-green-700
|
||||
{{else if eq "warn" .Rating }}border-amber-900 bg-amber-900/30 hover:bg-amber-900/50 hover:border-amber-700
|
||||
{{else if eq "bad" .Rating }}border-red-900 bg-red-900/30 hover:bg-red-900/50 hover:border-red-700
|
||||
{{else}}border-blue-900 bg-blue-900/30 hover:bg-blue-900/50 hover:border-blue-700
|
||||
{{end}}">
|
||||
|
||||
<span class="flex items-center">
|
||||
<!-- Icon -->
|
||||
<span class="flex-shrink-0">
|
||||
{{if eq "good" .Rating }}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-green-600 circle-check-filled" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M17 3.34a10 10 0 1 1 -14.995 8.984l-.005 -.324l.005 -.324a10 10 0 0 1 14.995 -8.336zm-1.293 5.953a1 1 0 0 0 -1.32 -.083l-.094 .083l-3.293 3.292l-1.293 -1.292l-.094 -.083a1 1 0 0 0 -1.403 1.403l.083 .094l2 2l.094 .083a1 1 0 0 0 1.226 0l.094 -.083l4 -4l.083 -.094a1 1 0 0 0 -.083 -1.32z" stroke-width="0" fill="currentColor"></path>
|
||||
</svg>
|
||||
{{else if eq "warn" .Rating }}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-amber-600 alert-triangle-filled" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M12 1.67c.955 0 1.845 .467 2.39 1.247l.105 .16l8.114 13.548a2.914 2.914 0 0 1 -2.307 4.363l-.195 .008h-16.225a2.914 2.914 0 0 1 -2.582 -4.2l.099 -.185l8.11 -13.538a2.914 2.914 0 0 1 2.491 -1.403zm.01 13.33l-.127 .007a1 1 0 0 0 0 1.986l.117 .007l.127 -.007a1 1 0 0 0 0 -1.986l-.117 -.007zm-.01 -7a1 1 0 0 0 -.993 .883l-.007 .117v4l.007 .117a1 1 0 0 0 1.986 0l.007 -.117v-4l-.007 -.117a1 1 0 0 0 -.993 -.883z" stroke-width="0" fill="currentColor"></path>
|
||||
</svg>
|
||||
{{else if eq "bad" .Rating }}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-red-600/75 alert-circle-filled" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M12 2c5.523 0 10 4.477 10 10a10 10 0 0 1 -19.995 .324l-.005 -.324l.004 -.28c.148 -5.393 4.566 -9.72 9.996 -9.72zm.01 13l-.127 .007a1 1 0 0 0 0 1.986l.117 .007l.127 -.007a1 1 0 0 0 0 -1.986l-.117 -.007zm-.01 -8a1 1 0 0 0 -.993 .883l-.007 .117v4l.007 .117a1 1 0 0 0 1.986 0l.007 -.117v-4l-.007 -.117a1 1 0 0 0 -.993 -.883z" stroke-width="0" fill="currentColor"></path>
|
||||
</svg>
|
||||
{{else }}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-blue-600 blue-circle-filled" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M12 2c5.523 0 10 4.477 10 10a10 10 0 0 1 -19.995 .324l-.005 -.324l.004 -.28c.148 -5.393 4.566 -9.72 9.996 -9.72zm0 9h-1l-.117 .007a1 1 0 0 0 0 1.986l.117 .007v3l.007 .117a1 1 0 0 0 .876 .876l.117 .007h1l.117 -.007a1 1 0 0 0 .876 -.876l.007 -.117l-.007 -.117a1 1 0 0 0 -.764 -.857l-.112 -.02l-.117 -.006v-3l-.007 -.117a1 1 0 0 0 -.876 -.876l-.117 -.007zm.01 -3l-.127 .007a1 1 0 0 0 0 1.986l.117 .007l.127 -.007a1 1 0 0 0 0 -1.986l-.117 -.007z" stroke-width="0" fill="currentColor"></path>
|
||||
</svg>
|
||||
{{end}}
|
||||
</span>
|
||||
<!-- End icon -->
|
||||
|
||||
<span class="flex-1 ml-2 overflow-hidden capitalize-first whitespace-nowrap overflow-ellipsis">
|
||||
{{.Title}}
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
37
src/frontend/templates/partials/attribute_line.templ
Normal file
@ -0,0 +1,37 @@
|
||||
package partials
|
||||
|
||||
import (
|
||||
"kycnot.me/internal/ent"
|
||||
"kycnot.me/internal/ent/attribute"
|
||||
)
|
||||
|
||||
templ AttributeLine(attr *ent.Attribute) {
|
||||
<a
|
||||
href={ templ.SafeURL("/attribute/" + attr.Slug) }
|
||||
class={
|
||||
"block py-1.5 px-3 text-center text-sm border rounded-lg transition duration-300",
|
||||
templ.KV("border-green-900 bg-green-900/30 hover:bg-green-900/50 hover:border-green-700", attr.Rating == attribute.RatingGood),
|
||||
templ.KV("border-red-900 bg-red-900/30 hover:bg-red-900/50 hover:border-red-700", attr.Rating == attribute.RatingBad),
|
||||
templ.KV("border-blue-900 bg-blue-900/30 hover:bg-blue-900/50 hover:border-blue-700", attr.Rating == attribute.RatingInfo),
|
||||
templ.KV("border-amber-900 bg-amber-900/30 hover:bg-amber-900/50 hover:border-amber-700", attr.Rating == attribute.RatingWarn),
|
||||
}
|
||||
>
|
||||
<span class="flex items-center">
|
||||
<span class="flex-shrink-0">
|
||||
switch attr.Rating {
|
||||
case attribute.RatingGood:
|
||||
<i class="text-green-600 icon-[tabler--circle-check-filled]"></i>
|
||||
case attribute.RatingBad:
|
||||
<i class="icon-[tabler--alert-circle-filled] text-red-600/75"></i>
|
||||
case attribute.RatingWarn:
|
||||
<i class="icon-[tabler--alert-triangle-filled] text-amber-600"></i>
|
||||
case attribute.RatingInfo:
|
||||
<i class="text-blue-600 icon-[tabler--info-circle-filled]"></i>
|
||||
}
|
||||
</span>
|
||||
<span class="flex-1 ml-2 overflow-hidden capitalize-first whitespace-nowrap overflow-ellipsis">
|
||||
{ attr.Title }
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
<div
|
||||
class="flex flex-col justify-center max-w-lg p-4 text-sm border rounded-lg md:text-base
|
||||
{{if eq . 0}} border-green-500/20 bg-green-500/10
|
||||
{{else if eq . 1}} border-lime-300/40 bg-lime-300/10
|
||||
{{else if eq . 2}} border-amber-700/40 bg-amber-600/20
|
||||
{{else if eq . 3}} border-red-600/40 bg-red-600/20
|
||||
{{end}}
|
||||
"
|
||||
>
|
||||
<h2 class="flex items-center space-x-2 text-lg font-bold">
|
||||
{{if eq . 0}}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-5 h-5 text-green-600 circle-check-filled"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path
|
||||
d="M17 3.34a10 10 0 1 1 -14.995 8.984l-.005 -.324l.005 -.324a10 10 0 0 1 14.995 -8.336zm-1.293 5.953a1 1 0 0 0 -1.32 -.083l-.094 .083l-3.293 3.292l-1.293 -1.292l-.094 -.083a1 1 0 0 0 -1.403 1.403l.083 .094l2 2l.094 .083a1 1 0 0 0 1.226 0l.094 -.083l4 -4l.083 -.094a1 1 0 0 0 -.083 -1.32z"
|
||||
stroke-width="0"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
{{else if eq . 1}}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-5 h-5 text-lime-400/70 circle-check"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"></path>
|
||||
<path d="M9 12l2 2l4 -4"></path>
|
||||
</svg>
|
||||
{{else if eq . 2}}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-5 h-5 text-amber-600 alert-triangle-filled"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path
|
||||
d="M12 1.67c.955 0 1.845 .467 2.39 1.247l.105 .16l8.114 13.548a2.914 2.914 0 0 1 -2.307 4.363l-.195 .008h-16.225a2.914 2.914 0 0 1 -2.582 -4.2l.099 -.185l8.11 -13.538a2.914 2.914 0 0 1 2.491 -1.403zm.01 13.33l-.127 .007a1 1 0 0 0 0 1.986l.117 .007l.127 -.007a1 1 0 0 0 0 -1.986l-.117 -.007zm-.01 -7a1 1 0 0 0 -.993 .883l-.007 .117v4l.007 .117a1 1 0 0 0 1.986 0l.007 -.117v-4l-.007 -.117a1 1 0 0 0 -.993 -.883z"
|
||||
stroke-width="0"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
{{else if eq . 3}}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-5 h-5 text-red-600 alert-octagon-filled"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path
|
||||
d="M14.897 1a4 4 0 0 1 2.664 1.016l.165 .156l4.1 4.1a4 4 0 0 1 1.168 2.605l.006 .227v5.794a4 4 0 0 1 -1.016 2.664l-.156 .165l-4.1 4.1a4 4 0 0 1 -2.603 1.168l-.227 .006h-5.795a3.999 3.999 0 0 1 -2.664 -1.017l-.165 -.156l-4.1 -4.1a4 4 0 0 1 -1.168 -2.604l-.006 -.227v-5.794a4 4 0 0 1 1.016 -2.664l.156 -.165l4.1 -4.1a4 4 0 0 1 2.605 -1.168l.227 -.006h5.793zm-2.887 14l-.127 .007a1 1 0 0 0 0 1.986l.117 .007l.127 -.007a1 1 0 0 0 0 -1.986l-.117 -.007zm-.01 -8a1 1 0 0 0 -.993 .883l-.007 .117v4l.007 .117a1 1 0 0 0 1.986 0l.007 -.117v-4l-.007 -.117a1 1 0 0 0 -.993 -.883z"
|
||||
stroke-width="0"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
{{end}}
|
||||
|
||||
<span> KYC LEVEL <b>{{.}}</b> </span>
|
||||
</h2>
|
||||
|
||||
{{if eq . 0}}
|
||||
<p class="mt-2 text-sm">
|
||||
The exchange ToS <b class="font-bold">do not mention</b> that it will ever
|
||||
request the user for a KYC verification.
|
||||
</p>
|
||||
{{else if eq . 1}}
|
||||
<p class="mt-2 text-sm">
|
||||
KYC is <b class="font-bold">not mentioned</b>, but this service
|
||||
<b class="font-bold">reserves the right to share data</b> with
|
||||
representatives of the authorities, block funds or reject transactions.
|
||||
</p>
|
||||
{{else if eq . 2}}
|
||||
<p class="mt-2 text-sm">
|
||||
The exchange
|
||||
<b class="font-bold">may request KYC from any user at any time</b>,
|
||||
typically triggered by an automated flag system, leading to a temporary
|
||||
block of funds.
|
||||
</p>
|
||||
{{else if eq . 3}}
|
||||
<p class="mt-2 text-sm">
|
||||
KYC is <b class="font-bold">mandatory to use some features</b>. A non-KYCed
|
||||
user can be required to verify their identity at any time or any moment for
|
||||
any reason.
|
||||
</p>
|
||||
{{end}}
|
||||
</div>
|
@ -1,50 +0,0 @@
|
||||
{{/* service_card.html */}}
|
||||
<a href="/service/{{.Name}}" class="w-full max-w-md">
|
||||
<div class="flex flex-col justify-between p-4 bg-gray-700 bg-opacity-30 rounded-lg border border-transparent shadow-lg backdrop-blur-md transition duration-500 hover:border-lime-600/70">
|
||||
<div class="flex items-center">
|
||||
<img src="/api/g/picture/{{.ID}}" alt="{{.Name}} logo" class="mr-4 w-12 h-12 rounded-full bg-white/10" />
|
||||
<div class="flex flex-col justify-center items-center text-lg font-bold text-white md:text-xl">
|
||||
<span class="flex items-center pb-1 w-full text-base font-bold">
|
||||
{{if .Verified}}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="inline size-5 text-blue-400/80 discount-check-filled" width="24"
|
||||
height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path
|
||||
d="M12.01 2.011a3.2 3.2 0 0 1 2.113 .797l.154 .145l.698 .698a1.2 1.2 0 0 0 .71 .341l.135 .008h1a3.2 3.2 0 0 1 3.195 3.018l.005 .182v1c0 .27 .092 .533 .258 .743l.09 .1l.697 .698a3.2 3.2 0 0 1 .147 4.382l-.145 .154l-.698 .698a1.2 1.2 0 0 0 -.341 .71l-.008 .135v1a3.2 3.2 0 0 1 -3.018 3.195l-.182 .005h-1a1.2 1.2 0 0 0 -.743 .258l-.1 .09l-.698 .697a3.2 3.2 0 0 1 -4.382 .147l-.154 -.145l-.698 -.698a1.2 1.2 0 0 0 -.71 -.341l-.135 -.008h-1a3.2 3.2 0 0 1 -3.195 -3.018l-.005 -.182v-1a1.2 1.2 0 0 0 -.258 -.743l-.09 -.1l-.697 -.698a3.2 3.2 0 0 1 -.147 -4.382l.145 -.154l.698 -.698a1.2 1.2 0 0 0 .341 -.71l.008 -.135v-1l.005 -.182a3.2 3.2 0 0 1 3.013 -3.013l.182 -.005h1a1.2 1.2 0 0 0 .743 -.258l.1 -.09l.698 -.697a3.2 3.2 0 0 1 2.269 -.944zm3.697 7.282a1 1 0 0 0 -1.414 0l-3.293 3.292l-1.293 -1.292l-.094 -.083a1 1 0 0 0 -1.32 1.497l2 2l.094 .083a1 1 0 0 0 1.32 -.083l4 -4l.083 -.094a1 1 0 0 0 -.083 -1.32z"
|
||||
stroke-width="0" fill="currentColor"></path>
|
||||
</svg>
|
||||
{{end}}
|
||||
<span class="flex-1 text-sm capitalize whitespace-nowrap sm:text-base ms-3">{{.Name}}</span>
|
||||
<span
|
||||
class="inline-flex justify-center items-center px-2 py-0.5 text-xs font-medium rounded ms-3
|
||||
{{if ge .Score 10}}
|
||||
bg-green-900 border-green-800
|
||||
{{else if gt .Score 8}}
|
||||
bg-green-800 border-green-700
|
||||
{{else if gt .Score 7}}
|
||||
bg-lime-900 border-lime-800
|
||||
{{else if gt .Score 6}}
|
||||
bg-lime-700/80 border-lime-600/80
|
||||
{{else if gt .Score 5}}
|
||||
bg-yellow-800 border-yellow-700
|
||||
{{else if eq .Score 5}}
|
||||
bg-orange-900 border-orange-800
|
||||
{{else}}
|
||||
bg-red-900 border-red-800
|
||||
{{end}}
|
||||
text-white/70">{{.Score}}</span>
|
||||
</span>
|
||||
|
||||
<span class="block pr-1 mt-2 text-xs font-normal text-opacity-60 text-white/60">{{shortText .Description | safe}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center items-center mt-4 text-xs">
|
||||
{{if eq .Type "exchange"}}
|
||||
<span class="px-2 py-1 mr-1 text-xs font-bold uppercase rounded border text-white/70 bg-zinc-900 border-zinc-700"> {{.Type}} </span>
|
||||
{{else}}
|
||||
<span class="px-2 py-1 mr-1 text-xs font-bold uppercase rounded border text-white/70 bg-zinc-900 border-zinc-700"> {{.Category}} </span>
|
||||
{{end}} {{partial "partials/service_icons" .}}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
63
src/frontend/templates/partials/service_card.templ
Normal file
@ -0,0 +1,63 @@
|
||||
package partials
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kycnot.me/internal/ent"
|
||||
)
|
||||
|
||||
func getScoreColor(s int) string {
|
||||
switch {
|
||||
case s >= 10:
|
||||
return "bg-green-900 border-green-800"
|
||||
case s > 8:
|
||||
return "bg-green-800 border-green-700"
|
||||
case s > 7:
|
||||
return "bg-lime-900 border-lime-800"
|
||||
case s > 6:
|
||||
return "bg-lime-700/80 border-lime-600/80"
|
||||
case s > 5:
|
||||
return "bg-yellow-800 border-yellow-700"
|
||||
case s == 5:
|
||||
return "bg-orange-900 border-orange-800"
|
||||
default:
|
||||
return "bg-red-900 border-red-800"
|
||||
}
|
||||
}
|
||||
|
||||
templ ServiceCard(service *ent.Service) {
|
||||
<a href={ templ.SafeURL(fmt.Sprintf("/service/%s", service.Slug)) } class="block w-full max-w-md">
|
||||
<div
|
||||
class="flex flex-col justify-between p-4 bg-gray-700 bg-opacity-30 rounded-lg border border-transparent shadow-lg backdrop-blur-md transition duration-500 hover:border-lime-600/70"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<img src={ "/static/images/" + service.Slug + ".jpg" } alt={ service.Name + " logo" } class="mr-4 w-12 h-12 rounded-full bg-white/10"/>
|
||||
<div class="flex flex-col justify-center items-center text-lg font-bold text-white md:text-xl">
|
||||
<span class="flex items-center pb-1 w-full text-base font-bold">
|
||||
if service.Verified {
|
||||
<i class="icon-[tabler--rosette-discount-check-filled] inline text-xl text-blue-400/80"></i>
|
||||
}
|
||||
<span class="flex-1 text-sm whitespace-nowrap sm:text-base ms-2">{ service.Name }</span>
|
||||
if !service.Pending {
|
||||
<span class={ "inline-flex justify-center items-center px-2 py-0.5 text-xs font-medium rounded ms-3 text-white/70 " + getScoreColor(service.Score) }>{ fmt.Sprintf("%d", service.Score) }</span>
|
||||
} else {
|
||||
<span class={ "inline-flex justify-center items-center px-2 py-0.5 text-xs font-medium rounded ms-3 text-white/70 bg-gray-900 border-gray-800" }>PENDING</span>
|
||||
}
|
||||
</span>
|
||||
<span class="px-1 mt-1.5 text-xs font-normal text-opacity-60 overflow-ellipsis text-white/60 line-clamp-2">
|
||||
{ service.Description }
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center items-center mt-4 text-xs">
|
||||
<span class="px-2 py-1 mr-1 text-xs font-bold uppercase rounded border text-white/70 bg-zinc-900 border-zinc-700">
|
||||
if service.Type == "exchange" {
|
||||
EXCHANGE
|
||||
} else {
|
||||
{ service.Category }
|
||||
}
|
||||
</span>
|
||||
@ServiceIcons(service)
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
<!-- Monero -->
|
||||
<span aria-label="XMR" data-balloon-pos="up" class="px-2 py-1 m-1 text-center text-white rounded border bg-zinc-900 border-zinc-700">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 {{if .Xmr}}text-orange-400/70{{else}} text-white/20 {{end}} tabler-coin-monero" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"></path>
|
||||
<path d="M4 16h4v-7l4 4l4 -4v7h4"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<!-- Bitcoin -->
|
||||
<span aria-label="BTC" data-balloon-pos="up" class="px-2 py-1 m-1 text-center text-white rounded border bg-zinc-900 border-zinc-700">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 {{if .Btc}} text-amber-400/70 {{else}} text-white/20 {{end}} coin-bitcoin" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"></path>
|
||||
<path d="M9 8h4.09c1.055 0 1.91 .895 1.91 2s-.855 2 -1.91 2c1.055 0 1.91 .895 1.91 2s-.855 2 -1.91 2h-4.09"></path>
|
||||
<path d="M10 12h4"></path>
|
||||
<path d="M10 7v10v-9"></path>
|
||||
<path d="M13 7v1"></path>
|
||||
<path d="M13 16v1"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<!-- Lightning -->
|
||||
<span aria-label="LN" data-balloon-pos="up" class="px-2 py-1 m-1 text-center text-white rounded border bg-zinc-900 border-zinc-700">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 {{if .Lightning}} text-sky-400/70 {{else}} text-white/20 {{end}} bolt" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M13 3l0 7l6 0l-8 11l0 -7l-6 0l8 -11"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<!-- Cash -->
|
||||
<span aria-label="CASH" data-balloon-pos="up" class="px-2 py-1 m-1 text-center text-white rounded border bg-zinc-900 border-zinc-700">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 {{if .Cash}} text-yellow-300/70 {{else}} text-white/20 {{end}}" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M9 14c0 1.657 2.686 3 6 3s6 -1.343 6 -3s-2.686 -3 -6 -3s-6 1.343 -6 3z"></path>
|
||||
<path d="M9 14v4c0 1.656 2.686 3 6 3s6 -1.344 6 -3v-4"></path>
|
||||
<path d="M3 6c0 1.072 1.144 2.062 3 2.598s4.144 .536 6 0c1.856 -.536 3 -1.526 3 -2.598c0 -1.072 -1.144 -2.062 -3 -2.598s-4.144 -.536 -6 0c-1.856 .536 -3 1.526 -3 2.598z"></path>
|
||||
<path d="M3 6v10c0 .888 .772 1.45 2 2"></path>
|
||||
<path d="M3 11c0 .888 .772 1.45 2 2"></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<!-- Fiat -->
|
||||
<span aria-label="FIAT" data-balloon-pos="up" class="px-2 py-1 m-1 text-center text-white rounded border bg-zinc-900 border-zinc-700">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 {{if .Fiat}}text-green-400/70{{else}} text-white/20 {{end}} building-bank" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M3 21l18 0"></path>
|
||||
<path d="M3 10l18 0"></path>
|
||||
<path d="M5 6l7 -3l7 3"></path>
|
||||
<path d="M4 10l0 11"></path>
|
||||
<path d="M20 10l0 11"></path>
|
||||
<path d="M8 14l0 3"></path>
|
||||
<path d="M12 14l0 3"></path>
|
||||
<path d="M16 14l0 3"></path>
|
||||
</svg>
|
||||
</span>
|
41
src/frontend/templates/partials/service_icons.templ
Normal file
@ -0,0 +1,41 @@
|
||||
package partials
|
||||
|
||||
import "kycnot.me/internal/ent"
|
||||
|
||||
templ ServiceIcons(service *ent.Service) {
|
||||
<span aria-label="XMR" data-balloon-pos="up" class="flex items-center justify-center py-1 px-1.5 mx-0.5 border rounded bg-zinc-900 border-zinc-700">
|
||||
<span
|
||||
class={ "icon-[tabler--coin-monero] text-base",
|
||||
templ.KV("text-orange-500/80", service.Xmr),
|
||||
templ.KV("text-white/30", !service.Xmr) }
|
||||
></span>
|
||||
</span>
|
||||
<span aria-label="BTC" data-balloon-pos="up" class="flex items-center justify-center py-1 px-1.5 mx-0.5 border rounded bg-zinc-900 border-zinc-700">
|
||||
<span
|
||||
class={ "icon-[tabler--coin-bitcoin] text-base" ,
|
||||
templ.KV("text-yellow-500/80", service.Btc),
|
||||
templ.KV("text-white/30", !service.Btc) }
|
||||
></span>
|
||||
</span>
|
||||
<span aria-label="Lightning" data-balloon-pos="up" class="flex items-center justify-center py-1 px-1.5 mx-0.5 border rounded bg-zinc-900 border-zinc-700">
|
||||
<span
|
||||
class={ "icon-[tabler--bolt] text-base" ,
|
||||
templ.KV("text-blue-500/80", service.Lightning),
|
||||
templ.KV("text-white/30", !service.Lightning) }
|
||||
></span>
|
||||
</span>
|
||||
<span aria-label="Cash" data-balloon-pos="up" class="flex items-center justify-center py-1 px-1.5 mx-0.5 border rounded bg-zinc-900 border-zinc-700">
|
||||
<span
|
||||
class={ "icon-[tabler--cash] text-base" ,
|
||||
templ.KV("text-green-500/80", service.Cash),
|
||||
templ.KV("text-white/30", !service.Cash) }
|
||||
></span>
|
||||
</span>
|
||||
<span aria-label="Fiat" data-balloon-pos="up" class="flex items-center justify-center py-1 px-1.5 mx-0.5 border rounded bg-zinc-900 border-zinc-700">
|
||||
<span
|
||||
class={ "icon-[tabler--building-bank] text-base" ,
|
||||
templ.KV("text-purple-500/80", service.Fiat),
|
||||
templ.KV("text-white/30", !service.Fiat) }
|
||||
></span>
|
||||
</span>
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<div class="px-3 py-2 mt-2 border rounded-md w-full
|
||||
{{if eq .Warning true}}border-amber-900 bg-amber-900/30{{end}}
|
||||
{{if eq .Warning false}}border-blue-900 bg-blue-900/30{{end}}">
|
||||
<h3 class="text-sm font-bold uppercase">{{.Title}}</h3>
|
||||
<p class="my-1.5 text-sm">{{.Details}}</p>
|
||||
{{if .Section}}
|
||||
<p class="text-xs text-gray-400 text-opacity-40">ToS section: <span>"{{.Section}}"</span></p>
|
||||
{{end}}
|
||||
</div>
|
@ -1,18 +0,0 @@
|
||||
<main class="py-2 text-lime-500">
|
||||
<div class="mb-2 text-center bg-transparent md:grid">
|
||||
<p class="font-mono text-2xl font-bold uppercase md:text-base">Pending Services</p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Services list -->
|
||||
<section class="flex items-center justify-center p-12 px-3 pt-4 m-4">
|
||||
{{if .Services}}
|
||||
<div class="grid max-w-6xl grid-cols-1 gap-3 md:grid-cols-3 lg:grid-cols-3">
|
||||
{{range .Services}}
|
||||
{{partial "partials/service_card" .}}
|
||||
{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
<h2 class="my-8 text-xl font-bold text-center">No pending services.</h2>
|
||||
{{end}}
|
||||
</section>
|
@ -1,236 +0,0 @@
|
||||
<section class="flex flex-col items-center w-full py-8">
|
||||
<h2 class="text-2xl font-bold">Request a service</h2>
|
||||
<small class="opacity-70">*This form requires JavaScript, <a class="text-lime-600" href="/about#request">read more
|
||||
here</a>.</small>
|
||||
|
||||
<form action="/new/service" method="POST" class="max-w-lg my-6 space-y-4 font-mono">
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="type">Service Type</label>
|
||||
<select name="type" id="type" required
|
||||
class="p-2 text-white uppercase border rounded-lg bg-opacity-30 bg-zinc-900 border-white/30">
|
||||
<option selected value="exchange">exchange</option>
|
||||
<option value="service">service</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="category-container" class="flex flex-col">
|
||||
<label class="font-bold" for="category">Service Category</label>
|
||||
<select name="category" id="category" required
|
||||
class="p-2 text-white capitalize border rounded-lg bg-opacity-30 bg-zinc-900 border-white/30">
|
||||
<option value="aggregator">aggregator</option>
|
||||
<option value="atm">physical atm</option>
|
||||
<option value="cloud">cloud storage</option>
|
||||
<option value="email">email</option>
|
||||
<option value="goods">goods</option>
|
||||
<option value="hosting">hosting / domains</option>
|
||||
<option value="market">market</option>
|
||||
<option value="proxy store">proxy store</option>
|
||||
<option value="sms">sms / phone number</option>
|
||||
<option value="tools">tools</option>
|
||||
<option value="vpn">vpn</option>
|
||||
<option value="vps">server hosting (vps)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="name">Service Name</label>
|
||||
<input
|
||||
class="p-2 text-white border rounded-lg placeholder-white/30 bg-opacity-30 bg-zinc-900 border-white/30"
|
||||
placeholder="Awesome exchange" type="text" name="name" id="name" required>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="description">Description</label>
|
||||
<textarea
|
||||
class="p-2 font-mono text-white border rounded-lg placeholder-white/30 bg-opacity-30 bg-zinc-900 border-white/30"
|
||||
name="description" id="description"
|
||||
placeholder="concise description about what the service is. max 500 characters." cols="30" rows="5"
|
||||
required minlength="60" maxlength="500"></textarea>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="urls">Service URL(s)</label>
|
||||
<small class="text-white/30">*If more than one, separate with commas.</small>
|
||||
<input
|
||||
class="p-2 text-white border rounded-lg placeholder-white/30 bg-opacity-30 bg-zinc-900 border-white/30"
|
||||
type="text" name="urls" id="urls" required placeholder="https://example.com">
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="logo_url">Logo URL</label>
|
||||
<input
|
||||
class="p-2 text-white border rounded-lg placeholder-white/30 bg-opacity-30 bg-zinc-900 border-white/30"
|
||||
type="text" name="logo_url" id="logo_url" placeholder="https://i.imgur.com/wwwHfCN.jpeg" required>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="tos_urls">ToS URL(s)</label>
|
||||
<small class="text-white/30">*If more than one, separate with commas.</small>
|
||||
<input
|
||||
class="p-2 text-white border rounded-lg placeholder-white/30 bg-opacity-30 bg-zinc-900 border-white/30"
|
||||
type="text" name="tos_urls" id="tos_urls" required placeholder="https://example.com/terms">
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="onion_urls">Tor Onion URL(s)</label>
|
||||
<small class="text-white/30">*If more than one, separate with commas.</small>
|
||||
<input
|
||||
class="p-2 text-white border rounded-lg placeholder-white/30 bg-opacity-30 bg-zinc-900 border-white/30"
|
||||
type="text" name="onion_urls" id="onion_urls" placeholder="http://zbiowkw...onion">
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="tags">Keywords</label>
|
||||
<small class="text-white/30">*If more than one, separate with commas.</small>
|
||||
<input
|
||||
class="p-2 text-white border rounded-lg placeholder-white/30 bg-opacity-30 bg-zinc-900 border-white/30"
|
||||
type="text" name="tags" id="tags" required placeholder="private,p2p, fast">
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-center justify-center pt-4 space-x-2">
|
||||
<h3 class="mb-2 text-xl">Accepted currencies</h3>
|
||||
<div class="flex space-x-4">
|
||||
<span class="flex flex-col items-center justify-center">
|
||||
<label class="text-xs uppercase" for="btc">Bitcoin</label>
|
||||
<input
|
||||
class="rounded-full outline-none appearance-none bg-opacity-30 bg-zinc-900 focus:ring-0 border-lime-500 text-lime-500"
|
||||
type="checkbox" {{if eq "on" .Filters.Btc}}checked{{end}} name="btc" id="btc">
|
||||
</span>
|
||||
<span class="flex flex-col items-center justify-center">
|
||||
<label class="text-xs uppercase" for="xmr">MONERO</label>
|
||||
<input
|
||||
class="rounded-full outline-none appearance-none bg-opacity-30 bg-zinc-900 focus:ring-0 border-lime-500 text-lime-500"
|
||||
type="checkbox" {{if eq "on" .Filters.Xmr}}checked{{end}} name="xmr" id="xmr">
|
||||
</span>
|
||||
<span class="flex flex-col items-center justify-center">
|
||||
<label class="text-xs uppercase" for="ln">LIGHTNING</label>
|
||||
<input
|
||||
class="rounded-full outline-none appearance-none bg-opacity-30 bg-zinc-900 focus:ring-0 border-lime-500 text-lime-500"
|
||||
type="checkbox" {{if eq "on" .Filters.Ln}}checked{{end}} name="ln" id="ln">
|
||||
</span>
|
||||
<span class="flex flex-col items-center justify-center">
|
||||
<label class="text-xs uppercase" for="fiat">FIAT</label>
|
||||
<input
|
||||
class="rounded-full outline-none appearance-none bg-opacity-30 bg-zinc-900 focus:ring-0 border-lime-500 text-lime-500"
|
||||
type="checkbox" {{if eq "on" .Filters.Fiat}}checked{{end}} name="fiat" id="fiat">
|
||||
</span>
|
||||
<span class="flex flex-col items-center justify-center">
|
||||
<label class="text-xs uppercase" for="cash">CASH</label>
|
||||
<input
|
||||
class="rounded-full outline-none appearance-none bg-opacity-30 bg-zinc-900 focus:ring-0 border-lime-500 text-lime-500"
|
||||
type="checkbox" {{if eq "on" .Filters.Cash}}checked{{end}} name="cash" id="cash">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<h3 class="font-bold">KYC Level</h3>
|
||||
|
||||
<label class="flex flex-row items-center p-2 border rounded-lg border-white/10" for="kyclevel0">
|
||||
<input type="radio" name="kyc_level" id="kyclevel0" value="0">
|
||||
<p class="ml-3"><b class="text-lime-400">Level 0</b>: No KYC ever. The ToS do not mention nor enforce
|
||||
any KYC/AML verification.</p>
|
||||
</label>
|
||||
<label class="flex flex-row items-center p-2 border rounded-lg border-white/10" for="kyclevel1">
|
||||
<input type="radio" name="kyc_level" id="kyclevel1" value="1">
|
||||
<p class="ml-3"><b class="text-lime-400">Level 1</b>: No KYC/AML procedures are mentioned as such,
|
||||
however the service reserves the right to share acquired data with authorities, block funds or
|
||||
reject transactions.</p>
|
||||
</label>
|
||||
<label class="flex flex-row items-center p-2 border rounded-lg border-white/10" for="kyclevel2">
|
||||
<input type="radio" name="kyc_level" id="kyclevel2" value="2" checked>
|
||||
<p class="ml-3"><b class="text-lime-400">Level 2</b>: KYC is not mandatory, but the service can require
|
||||
KYC from any user at any time, and it may block funds. This could occur, for example, if a
|
||||
transaction is flagged suspicious.</p>
|
||||
</label>
|
||||
<label class="flex flex-row items-center p-2 border rounded-lg border-white/10" for="kyclevel3">
|
||||
<input type="radio" name="kyc_level" id="kyclevel3" value="3">
|
||||
<p class="ml-3"><b class="text-lime-400">Level 3</b>: KYC is mandatory to use certain features of the
|
||||
platform. Non-KYC users can be asked to verify their identity at any time, for any reason and may
|
||||
have their service restricted or revoked.</p>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<h3 class="font-bold">Attributes</h3>
|
||||
<small class="text-white/50">* Scrollable. You must check at least 3</small>
|
||||
<div class="max-w-lg p-4 mx-4 mb-4 space-y-2 overflow-scroll border rounded-lg h-52 border-white/10">
|
||||
{{range .Attributes}}
|
||||
<span class="block p-1 border-b border-white/10">
|
||||
<input type="checkbox" id="{{.ID}}" name="attributes" value="{{.ID}}">
|
||||
<label class="ml-1
|
||||
{{if eq .Rating " info"}}text-blue-400/80{{end}} {{if eq .Rating "good"
|
||||
}}text-green-400/80{{end}} {{if eq .Rating "warn" }}text-yellow-400/80{{end}} {{if eq .Rating "bad"
|
||||
}}text-red-400/80{{end}} " for=" {{.ID}}">{{.Title}}</label>
|
||||
</span>
|
||||
{{end}}
|
||||
</div>
|
||||
<noscript>
|
||||
<p class="my-2 font-bold text-yellow-500 uppercase">
|
||||
You need to enable JavaScript to complete this form.
|
||||
</p>
|
||||
</noscript>
|
||||
<div id="start-pow"
|
||||
class="flex items-center justify-center px-4 py-2 mt-2 mb-4 space-x-2 font-bold uppercase bg-blue-900 rounded-lg cursor-pointer"
|
||||
data-pow="{{.Pow.Id}}" data-pow-c="{{.Pow.Challenge}}" data-pow-d="{{.Pow.Difficulty}}">
|
||||
<input type="text" name="pow-nonce" id="pow-nonce" hidden required value="">
|
||||
<input type="text" name="pow-id" id="pow-id" hidden required value="{{.Pow.Id}}">
|
||||
<svg id="pow-spinner" class="hidden text-white fill-white" width="24" height="24" viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
.spinner_ZCsl {
|
||||
animation: spinner_qV4G 1.2s cubic-bezier(0.52, .6, .25, .99) infinite
|
||||
}
|
||||
|
||||
.spinner_gaIW {
|
||||
animation-delay: .6s
|
||||
}
|
||||
|
||||
@keyframes spinner_qV4G {
|
||||
0% {
|
||||
r: 0;
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
100% {
|
||||
r: 11px;
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<circle class="spinner_ZCsl" cx="12" cy="12" r="0" />
|
||||
<circle class="spinner_ZCsl spinner_gaIW" cx="12" cy="12" r="0" />
|
||||
</svg>
|
||||
<span id="pow-text">🧠 I'm Human</span>
|
||||
</div>
|
||||
<button id="submit-btn"
|
||||
class="hidden w-full px-4 py-2 my-4 space-x-2 font-bold uppercase rounded-lg cursor-pointer bg-lime-900">
|
||||
Submit
|
||||
</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
|
||||
<script src="/static/js/pow.js"></script>
|
||||
<script>
|
||||
// Initialize PoW service
|
||||
startPow();
|
||||
|
||||
// Toggle category select based on type select
|
||||
document.addEventListener('DOMContentLoaded', (event) => {
|
||||
const typeSelect = document.getElementById('type');
|
||||
const categoryDiv = document.getElementById('category-container');
|
||||
|
||||
function toggleCategory() {
|
||||
if (typeSelect.value === 'service') {
|
||||
categoryDiv.style.display = 'flex'; // Show
|
||||
} else {
|
||||
categoryDiv.style.display = 'none'; // Hide
|
||||
}
|
||||
}
|
||||
// Initial toggle based on the preselected option
|
||||
toggleCategory();
|
||||
// Add change event listener to the type select element
|
||||
typeSelect.addEventListener('change', toggleCategory);
|
||||
});
|
||||
</script>
|
@ -1,379 +0,0 @@
|
||||
<head>
|
||||
<script type="text/javascript" src="/static/js/cactus.js"></script>
|
||||
<link rel="stylesheet" href="/static/css/cactus.css" type="text/css">
|
||||
</head>
|
||||
|
||||
<section class="flex flex-col items-center justify-center p-2 my-4 mt-8 mb-2 space-y-4 font-bold text-md md:text-md">
|
||||
<!-- Pending Approval Notice -->
|
||||
{{if .Service.Pending}}
|
||||
<div class="flex items-center justify-center">
|
||||
<a href="#" target="_blank" class="flex items-center justify-center px-2 py-1 m-1 space-x-2 text-center text-yellow-500 transition duration-300 border border-yellow-600 rounded bg-zinc-900 hover:border-yellow-600 hover:text-yellow-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 text-yellow-600 tabler-alert" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<circle cx="12" cy="12" r="9"></circle>
|
||||
<line x1="12" y1="8" x2="12" y2="12"></line>
|
||||
<line x1="12" y1="16" x2="12.01" y2="16"></line>
|
||||
</svg>
|
||||
<span>Pending approval</span>
|
||||
</a>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<!-- Not Listed Notice -->
|
||||
{{if and (not .Service.Pending) (not .Service.Listed)}}
|
||||
<div class="flex items-center justify-center">
|
||||
<a href="#" target="_blank"
|
||||
class="flex items-center justify-center px-2 py-1 m-1 space-x-2 text-center text-yellow-500 transition duration-300 border border-yellow-600 rounded bg-zinc-900 hover:border-yellow-600 hover:text-yellow-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 text-yellow-600 tabler-alert" width="24" height="24"
|
||||
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<circle cx="12" cy="12" r="9"></circle>
|
||||
<line x1="12" y1="8" x2="12" y2="12"></line>
|
||||
<line x1="12" y1="16" x2="12.01" y2="16"></line>
|
||||
</svg>
|
||||
<span>DELISTED</span>
|
||||
</a>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<!-- Display Service Notes -->
|
||||
{{if not (eq (len .Service.Notes) 0)}}
|
||||
{{range .Service.Notes}}
|
||||
{{if ne . ""}}
|
||||
<p class="max-w-lg p-4 text-sm border rounded-lg md:text-base border-yellow-400/20 bg-yellow-500/10">
|
||||
{{.}}
|
||||
</p>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
|
||||
<!-- Service Header -->
|
||||
<div class="flex items-center justify-center space-x-4">
|
||||
<img class="rounded-full size-10 md:size-14 bg-white/25" src="/api/g/picture/{{.Service.ID}}" alt="" />
|
||||
<span class="flex items-center justify-center capitalize">
|
||||
<span class="text-xl font-bold md:text-2xl">{{.Service.Name}}</span>
|
||||
{{if .Service.Verified}}
|
||||
<a aria-label="Verified" data-balloon-pos="up" href="/static/proofs/{{lower .Service.Name}}/proof.txt.asc">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 ml-1 {{if .Service.Verified}}text-blue-400/80{{else}} text-white/20 {{end}} discount-check-filled" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path
|
||||
d="M12.01 2.011a3.2 3.2 0 0 1 2.113 .797l.154 .145l.698 .698a1.2 1.2 0 0 0 .71 .341l.135 .008h1a3.2 3.2 0 0 1 3.195 3.018l.005 .182v1c0 .27 .092 .533 .258 .743l.09 .1l.697 .698a3.2 3.2 0 0 1 .147 4.382l-.145 .154l-.698 .698a1.2 1.2 0 0 0 -.341 .71l-.008 .135v1a3.2 3.2 0 0 1 -3.018 3.195l-.182 .005h-1a1.2 1.2 0 0 0 -.743 .258l-.1 .09l-.698 .697a3.2 3.2 0 0 1 -4.382 .147l-.154 -.145l-.698 -.698a1.2 1.2 0 0 0 -.71 -.341l-.135 -.008h-1a3.2 3.2 0 0 1 -3.195 -3.018l-.005 -.182v-1a1.2 1.2 0 0 0 -.258 -.743l-.09 -.1l-.697 -.698a3.2 3.2 0 0 1 -.147 -4.382l.145 -.154l.698 -.698a1.2 1.2 0 0 0 .341 -.71l.008 -.135v-1l.005 -.182a3.2 3.2 0 0 1 3.013 -3.013l.182 -.005h1a1.2 1.2 0 0 0 .743 -.258l.1 -.09l.698 -.697a3.2 3.2 0 0 1 2.269 -.944zm3.697 7.282a1 1 0 0 0 -1.414 0l-3.293 3.292l-1.293 -1.292l-.094 -.083a1 1 0 0 0 -1.32 1.497l2 2l.094 .083a1 1 0 0 0 1.32 -.083l4 -4l.083 -.094a1 1 0 0 0 -.083 -1.32z"
|
||||
stroke-width="0"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
{{end}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Links -->
|
||||
<div class="flex flex-wrap items-center justify-center space-x-2">
|
||||
{{if ne (len .Service.Urls) 0}}
|
||||
<div class="inline-flex">
|
||||
<a href="{{randomElem .Service.Urls}}{{.Service.Referral}}" target="_blank"
|
||||
class="flex justify-center items-center px-2 py-1 space-x-1 text-center text-gray-300
|
||||
{{if ne .Service.Referral ""}}rounded-l{{else}}rounded{{end}}
|
||||
border border-gray-600 transition duration-300 bg-zinc-900 hover:border-lime-600 hover:text-lime-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 tabler-world-www" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M19.5 7a9 9 0 0 0 -7.5 -4a8.991 8.991 0 0 0 -7.484 4"></path>
|
||||
<path d="M11.5 3a16.989 16.989 0 0 0 -1.826 4"></path>
|
||||
<path d="M12.5 3a16.989 16.989 0 0 1 1.828 4"></path>
|
||||
<path d="M19.5 17a9 9 0 0 1 -7.5 4a8.991 8.991 0 0 1 -7.484 -4"></path>
|
||||
<path d="M11.5 21a16.989 16.989 0 0 1 -1.826 -4"></path>
|
||||
<path d="M12.5 21a16.989 16.989 0 0 0 1.828 -4"></path>
|
||||
<path d="M2 10l1 4l1.5 -4l1.5 4l1 -4"></path>
|
||||
<path d="M17 10l1 4l1.5 -4l1.5 4l1 -4"></path>
|
||||
<path d="M9.5 10l1 4l1.5 -4l1.5 4l1 -4"></path>
|
||||
</svg>
|
||||
<span>Website</span>
|
||||
</a>
|
||||
|
||||
{{if ne .Service.Referral ""}}
|
||||
<a aria-label="No Referral" data-balloon-pos="up" href="{{randomElem .Service.Urls}}" class="flex items-center justify-center px-1 py-1 text-center text-gray-300 transition duration-300 border border-gray-600 rounded-r md:px-2 bg-zinc-900 hover:border-lime-600 hover:text-lime-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="size-4 link-off" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M9 15l3 -3m2 -2l1 -1" />
|
||||
<path d="M11 6l.463 -.536a5 5 0 0 1 7.071 7.072l-.534 .464" />
|
||||
<path d="M3 3l18 18" />
|
||||
<path d="M13 18l-.397 .534a5.068 5.068 0 0 1 -7.127 0a4.972 4.972 0 0 1 0 -7.071l.524 -.463" />
|
||||
</svg>
|
||||
</a>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if ne (len .Service.OnionUrls) 0}}
|
||||
<div class="inline-flex">
|
||||
<a href="{{randomElem .Service.OnionUrls}}{{.Service.Referral}}" target="_blank"
|
||||
class="flex justify-center items-center px-2 py-1 space-x-1 text-center text-purple-600
|
||||
{{if ne .Service.Referral ""}}rounded-l{{else}}rounded{{end}}
|
||||
border border-purple-900 transition duration-300 bg-zinc-900 hover:border-lime-600 hover:text-lime-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 tabler-target" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M12 12m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path>
|
||||
<path d="M12 12m-5 0a5 5 0 1 0 10 0a5 5 0 1 0 -10 0"></path>
|
||||
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"></path>
|
||||
</svg>
|
||||
|
||||
{{if eq (len .Service.Urls) 0}}
|
||||
<span>Tor Only</span>
|
||||
{{else}}
|
||||
<span>Tor</span>
|
||||
{{end}}
|
||||
|
||||
{{if ne .Service.Referral ""}}
|
||||
<a aria-label="No Referral" data-balloon-pos="up" href="{{randomElem .Service.OnionUrls}}" class="flex items-center justify-center px-1 py-1 text-center text-purple-600 transition duration-300 border border-purple-900 rounded-r md:px-2 bg-zinc-900 hover:border-lime-600 hover:text-lime-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="size-4 link-off" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M9 15l3 -3m2 -2l1 -1" />
|
||||
<path d="M11 6l.463 -.536a5 5 0 0 1 7.071 7.072l-.534 .464" />
|
||||
<path d="M3 3l18 18" />
|
||||
<path d="M13 18l-.397 .534a5.068 5.068 0 0 1 -7.127 0a4.972 4.972 0 0 1 0 -7.071l.524 -.463" />
|
||||
</svg>
|
||||
</a>
|
||||
{{end}}
|
||||
</a>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if ne (len .Service.TosUrls) 0}}
|
||||
<a href="{{index .Service.TosUrls 0}}" target="_blank" class="flex items-center justify-center px-2 py-1 m-1 space-x-2 text-center text-gray-300 transition duration-300 border border-gray-600 rounded bg-zinc-900 hover:border-lime-600 hover:text-lime-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 tabler-report-search" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M8 5h-2a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h5.697"></path>
|
||||
<path d="M18 12v-5a2 2 0 0 0 -2 -2h-2"></path>
|
||||
<path d="M8 3m0 2a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v0a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2z"></path>
|
||||
<path d="M8 11h4"></path>
|
||||
<path d="M8 15h3"></path>
|
||||
<path d="M16.5 17.5m-2.5 0a2.5 2.5 0 1 0 5 0a2.5 2.5 0 1 0 -5 0"></path>
|
||||
<path d="M18.5 19.5l2.5 2.5"></path>
|
||||
</svg>
|
||||
<span>ToS</span>
|
||||
</a>
|
||||
{{end}}
|
||||
|
||||
<a aria-label="Discuss service" data-balloon-pos="up" href="#discuss" class="items-center justify-center hidden px-2 py-1 m-1 space-x-2 text-center transition duration-300 border rounded text-sky-400 border-sky-700 md:flex bg-zinc-900 hover:border-lime-600 hover:text-lime-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 messages" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M21 14l-3 -3h-7a1 1 0 0 1 -1 -1v-6a1 1 0 0 1 1 -1h9a1 1 0 0 1 1 1v10"></path>
|
||||
<path d="M14 15v2a1 1 0 0 1 -1 1h-7l-3 3v-10a1 1 0 0 1 1 -1h2"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Usage Guide Button -->
|
||||
<!--<div class="flex flex-col items-center justify-center my-1 text-sm">
|
||||
<a href="https://example.com" target="_blank" class="flex items-center justify-center max-w-xs px-2 py-1 m-1 space-x-2 text-center transition duration-300 border rounded text-lime-400 border-lime-700 bg-zinc-900 hover:border-lime-600 hover:text-lime-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 compass" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M8 16l2 -6l6 -2l-2 6l-6 2"></path>
|
||||
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"></path>
|
||||
<path d="M12 3l0 2"></path>
|
||||
<path d="M12 19l0 2"></path>
|
||||
<path d="M3 12l2 0"></path>
|
||||
<path d="M19 12l2 0"></path>
|
||||
</svg>
|
||||
<span>Usage Guide</span>
|
||||
</a>
|
||||
</div>-->
|
||||
|
||||
<!-- Icons -->
|
||||
<a href="/about#icons" class="flex items-center justify-center max-w-md mt-4 text-xs"> {{partial "partials/service_icons" .Service}} </a>
|
||||
|
||||
<!-- Description -->
|
||||
<p class="max-w-lg p-4 text-sm border rounded-lg md:text-base border-white/20 bg-gray-500/10">{{if ne .Service.Description ""}} {{.Service.Description | safe}} {{else}} This {{.Service.Type}} does not have a description. {{end}}</p>
|
||||
</section>
|
||||
|
||||
<!-- KYC Level -->
|
||||
<section class="flex items-center justify-center px-2">{{partial "partials/kyc_level" .Service.KycLevel}}</section>
|
||||
|
||||
<section class="flex flex-col items-center justify-center p-4">
|
||||
<!-- Notes / Comments -->
|
||||
{{if .Service.Comments}}
|
||||
<div class="mb-5 space-y-1.5 max-w-lg">
|
||||
{{range .Service.Comments}}
|
||||
<p
|
||||
class="block px-3 py-1.5 text-sm font-bold rounded-lg border transition duration-300 border-amber-300/30 bg-amber-300/10 hover:bg-amber-300/20 hover:border-amber-100/50">
|
||||
{{ . | safe }}</p>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<!-- Attributes -->
|
||||
{{if .Attributes}}
|
||||
<div class="grid grid-cols-1 gap-2 mt-2 auto-cols-max md:grid-cols-2">{{range .Attributes}} {{partial "partials/attribute_line" .}} {{end}}</div>
|
||||
{{end}}
|
||||
</section>
|
||||
|
||||
<!-- SERVICE CONTACT -->
|
||||
{{if gt (len .Service.SupportMethods) 0}}
|
||||
<section id="contact" class="flex flex-col items-center justify-center p-4">
|
||||
<h3 class="mb-2 font-bold text-center uppercase text-md">Contact</h3>
|
||||
<ul
|
||||
class="flex items-center justify-center gap-2 flex-wrap text-sm [&>li>a]:p-2 [&>li>a]:rounded [&>li>a]:bg-white/10 hover:[&>li>a]:bg-white/20 [&>li>a]:transition [&>li>a]:duration-200">
|
||||
{{ range .Service.SupportMethods }}
|
||||
{{ if eq .Platform "telegram"}}
|
||||
<li class="text-center">
|
||||
<a class="flex items-center justify-center space-x-2" href="https://t.me/{{.Link}}">
|
||||
<svg class="size-5 fill-blue-300" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Telegram</title>
|
||||
<path
|
||||
d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z" />
|
||||
</svg>
|
||||
<span>@{{.Link}}</span>
|
||||
</a>
|
||||
</li>
|
||||
{{ else if or (eq .Platform "mail") (eq .Platform "email") }}
|
||||
<li class="text-center">
|
||||
<a class="flex items-center justify-center space-x-2">
|
||||
<svg class="size-4 fill-white/80" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Mail</title>
|
||||
<path
|
||||
d="M15.61 12c0 1.99-1.62 3.61-3.61 3.61-1.99 0-3.61-1.62-3.61-3.61 0-1.99 1.62-3.61 3.61-3.61 1.99 0 3.61 1.62 3.61 3.61M12 0C5.383 0 0 5.383 0 12s5.383 12 12 12c2.424 0 4.761-.722 6.76-2.087l.034-.024-1.617-1.879-.027.017A9.494 9.494 0 0 1 12 21.54c-5.26 0-9.54-4.28-9.54-9.54 0-5.26 4.28-9.54 9.54-9.54 5.26 0 9.54 4.28 9.54 9.54a9.63 9.63 0 0 1-.225 2.05c-.301 1.239-1.169 1.618-1.82 1.568-.654-.053-1.42-.52-1.426-1.661V12A6.076 6.076 0 0 0 12 5.93 6.076 6.076 0 0 0 5.93 12 6.076 6.076 0 0 0 12 18.07a6.02 6.02 0 0 0 4.3-1.792 3.9 3.9 0 0 0 3.32 1.805c.874 0 1.74-.292 2.437-.821.719-.547 1.256-1.336 1.553-2.285.047-.154.135-.504.135-.507l.002-.013c.175-.76.253-1.52.253-2.457 0-6.617-5.383-12-12-12" />
|
||||
</svg>
|
||||
<span>{{mailsafe .Link}}</span>
|
||||
</a>
|
||||
</li>
|
||||
{{ else if eq .Platform "url" }}
|
||||
<li class="text-center">
|
||||
<a class="flex items-center justify-center space-x-2" href="{{.Link}}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon size-5 icon-tabler icon-tabler-external-link" width="44"
|
||||
height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#ffffff" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M12 6h-6a2 2 0 0 0 -2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-6" />
|
||||
<path d="M11 13l9 -9" />
|
||||
<path d="M15 4h5v5" />
|
||||
</svg>
|
||||
<span>Contact Page</span>
|
||||
</a>
|
||||
</li>
|
||||
{{ else if eq .Platform "simplex" }}
|
||||
<li class="text-center hover:underline">
|
||||
<a class="flex items-center justify-center space-x-2" class="size-5 fill-white" href="{{.Link}}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
||||
<path fill="currentColor"
|
||||
d="M3 5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2zm4 13h2l.35-2h4L13 18h2l.35-2h2l.36-2h-2l.7-4h2l.35-2h-2l.36-2h-2l-.36 2h-4l.36-2h-2l-.36 2h-2l-.35 2h2l-.7 4h-2l-.36 2h2zm3.41-8h4l-.7 4h-4z" />
|
||||
</svg>
|
||||
<span>SimpleX</span>
|
||||
</a>
|
||||
</li>
|
||||
{{else if eq .Platform "matrix" }}
|
||||
<li class="text-center hover:underline">
|
||||
<a class="flex items-center justify-center space-x-2" href="{{.Link}}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="size-5 fill-white" width="1em" height="1em" viewBox="0 0 256 256">
|
||||
<path fill="currentColor"
|
||||
d="M208 32H48a16 16 0 0 0-16 16v160a16 16 0 0 0 16 16h160a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16M80 200H64a8 8 0 0 1-8-8V64a8 8 0 0 1 8-8h16a8 8 0 0 1 0 16h-8v112h8a8 8 0 0 1 0 16m80-40a8 8 0 0 1-8-8v-32a8 8 0 0 0-16 0v32a8 8 0 0 1-16 0v-32a8 8 0 0 0-16 0v32a8 8 0 0 1-16 0v-48a8 8 0 0 1 13.66-5.65a23.94 23.94 0 0 1 26.34 3.78A24 24 0 0 1 168 120v32a8 8 0 0 1-8 8m40 32a8 8 0 0 1-8 8h-16a8 8 0 0 1 0-16h8V72h-8a8 8 0 0 1 0-16h16a8 8 0 0 1 8 8Z" />
|
||||
</svg>
|
||||
<span>Matrix</span>
|
||||
</a>
|
||||
</li>
|
||||
{{else if eq .Platform "x" }}
|
||||
<li class="text-center hover:underline">
|
||||
<a class="flex items-center justify-center space-x-2" href="{{.Link}}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="size-5 fill-white" width="0.88em" height="1em" viewBox="0 0 448 512">
|
||||
<path fill="currentColor"
|
||||
d="M64 32C28.7 32 0 60.7 0 96v320c0 35.3 28.7 64 64 64h320c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64zm297.1 84L257.3 234.6L379.4 396h-95.6L209 298.1L123.3 396H75.8l111-126.9L69.7 116h98l67.7 89.5l78.2-89.5zm-37.8 251.6L153.4 142.9h-28.3l171.8 224.7h26.3z" />
|
||||
</svg>
|
||||
<span>X</span>
|
||||
</a>
|
||||
</li>
|
||||
{{else if eq .Platform "mastodon" }}
|
||||
<li class="text-center hover:underline">
|
||||
<a class="flex items-center justify-center space-x-2" href="{{.Link}}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="size-5 fill-white" width="1em" height="1em" viewBox="0 0 24 24">
|
||||
<path fill="white"
|
||||
d="M20.94 14c-.28 1.41-2.44 2.96-4.97 3.26c-1.31.15-2.6.3-3.97.24c-2.25-.11-4-.54-4-.54v.62c.32 2.22 2.22 2.35 4.03 2.42c1.82.05 3.44-.46 3.44-.46l.08 1.65s-1.28.68-3.55.81c-1.25.07-2.81-.03-4.62-.5c-3.92-1.05-4.6-5.24-4.7-9.5l-.01-3.43c0-4.34 2.83-5.61 2.83-5.61C6.95 2.3 9.41 2 11.97 2h.06c2.56 0 5.02.3 6.47.96c0 0 2.83 1.27 2.83 5.61c0 0 .04 3.21-.39 5.43M18 8.91c0-1.08-.3-1.91-.85-2.56c-.56-.63-1.3-.96-2.23-.96c-1.06 0-1.87.41-2.42 1.23l-.5.88l-.5-.88c-.56-.82-1.36-1.23-2.43-1.23c-.92 0-1.66.33-2.23.96C6.29 7 6 7.83 6 8.91v5.26h2.1V9.06c0-1.06.45-1.62 1.36-1.62c1 0 1.5.65 1.5 1.93v2.79h2.07V9.37c0-1.28.5-1.93 1.51-1.93c.9 0 1.35.56 1.35 1.62v5.11H18z" />
|
||||
</svg>
|
||||
<span>Mastodon</span>
|
||||
</a>
|
||||
</li>
|
||||
{{else}}
|
||||
<li class="text-center hover:underline">
|
||||
<a class="flex items-center justify-center space-x-2" href="{{.Link}}">
|
||||
<span>{{.Platform}}</span>
|
||||
</a>
|
||||
</li>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</ul>
|
||||
</section>
|
||||
{{end}}
|
||||
<!-- END SERVICE CONTACT -->
|
||||
|
||||
<div class="w-full my-2 border-t-2 border-opacity-50 border-dashed border-t-lime-400/10"></div>
|
||||
|
||||
<!-- ToS Checker -->
|
||||
<section class="flex flex-col items-center justify-center p-4" id="tos">
|
||||
<a href="/about#tos-checker" class="text-xl font-bold">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="inline-block w-4 h-4 calendar-cog" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M12 21h-6a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v5"></path>
|
||||
<path d="M16 3v4"></path>
|
||||
<path d="M8 3v4"></path>
|
||||
<path d="M4 11h16"></path>
|
||||
<path d="M19.001 19m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"></path>
|
||||
<path d="M19.001 15.5v1.5"></path>
|
||||
<path d="M19.001 21v1.5"></path>
|
||||
<path d="M22.032 17.25l-1.299 .75"></path>
|
||||
<path d="M17.27 20l-1.3 .75"></path>
|
||||
<path d="M15.97 17.25l1.3 .75"></path>
|
||||
<path d="M20.733 20l1.3 .75"></path>
|
||||
</svg>
|
||||
<span>ToS Review</span>
|
||||
<span class="text-xs text-white/30">?</span>
|
||||
</a>
|
||||
<p class="max-w-sm text-xs text-center text-gray-500 text-opacity-75">Automated, ai-driven monthly ToS reviews.</p>
|
||||
<p class="max-w-sm mt-1 text-xs text-center text-gray-600 text-opacity-75">Last Check: {{ dateString .Service.LastTosReview }}</p>
|
||||
|
||||
{{if .Service.TosReviews}}
|
||||
<div class="max-w-lg">
|
||||
{{if eq 0 (len .Service.TosReviews)}}
|
||||
<p class="max-w-md mt-2 font-bold text-center text-opacity-75 text-amber-400 text-md">Not ToS reviews for this service (yet).</p>
|
||||
{{else if eq (len .Service.TosUrls) 0}}
|
||||
<p class="max-w-md mt-2 font-bold text-center text-opacity-75 text-amber-400 text-md">This service has no ToS.</p>
|
||||
{{else}} {{range .Service.TosReviews}} {{if .Warning}} {{partial "partials/tos_check" .}} {{end}} {{end}}
|
||||
<details class="py-2">
|
||||
<summary class="max-w-md mt-2 text-lg font-bold text-center text-blue-400 text-opacity-75 cursor-pointer">Show non-conflictive ToS reviews</summary>
|
||||
{{range .Service.TosReviews}} {{if ne .Warning true}} {{partial "partials/tos_check" .}} {{end}} {{end}}
|
||||
</details>
|
||||
{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
<p class="max-w-md mt-2 font-bold text-center text-opacity-75 text-amber-400 text-md">Not ToS reviews for this service (yet).</p>
|
||||
{{end}}
|
||||
</section>
|
||||
|
||||
<div class="w-full my-2 border-t-2 border-opacity-50 border-dashed border-t-lime-400/10"></div>
|
||||
|
||||
<!-- Comments -->
|
||||
<section class="flex flex-col items-center justify-center p-4 mb-16" id="discuss">
|
||||
<a href="/about#comments" target="_blank" class="text-xl font-bold">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="inline-block w-4 h-4 messages" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M21 14l-3 -3h-7a1 1 0 0 1 -1 -1v-6a1 1 0 0 1 1 -1h9a1 1 0 0 1 1 1v10"></path>
|
||||
<path d="M14 15v2a1 1 0 0 1 -1 1h-7l-3 3v-10a1 1 0 0 1 1 -1h2"></path>
|
||||
</svg>
|
||||
<span>Comments</span>
|
||||
<span class="text-xs text-white/30">?</span>
|
||||
</a>
|
||||
<h2 class="text-xl font-bold"></h2>
|
||||
<p class="max-w-sm pb-4 mt-1 text-xs text-center text-gray-500 text-opacity-75">Alghough comments are moderated, beware of fake reviews. Always do your own research.</p>
|
||||
<!-- Div where cactus will set the client-->
|
||||
<div id="comment-section" class="w-full max-w-xl mx-2 break-all sm:mx-6">
|
||||
<comentario-comments></comentario-comments>
|
||||
<noscript>
|
||||
<p class="mb-2 font-bold text-center text-yellow-300">
|
||||
You can enable JavaScript to see and use comments here. It just will load a 20kb open-source script to interact with our instance of Comentario.
|
||||
The source code is available on <a target="_blank" class="underline" href="https://gitlab.com/commento/commento">Gitlab</a>.
|
||||
</p>
|
||||
</noscript>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script defer src="https://comments.kycnot.me/comentario.js"></script>
|
343
src/frontend/templates/service.templ
Normal file
@ -0,0 +1,343 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kycnot.me/frontend/templates/partials"
|
||||
"kycnot.me/internal/ent"
|
||||
"kycnot.me/utils"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func formatNote(n string) string {
|
||||
if n == "" {
|
||||
return ""
|
||||
}
|
||||
baseClasses := "max-w-lg p-2 text-sm border rounded-lg font-normal"
|
||||
prefixes := map[string]struct {
|
||||
icon string
|
||||
classes string
|
||||
}{
|
||||
"info:": {"icon-[tabler--info-circle]", "border-blue-400/20 text-blue-50/80 bg-blue-500/10"},
|
||||
"warning:": {"icon-[tabler--alert-triangle]", "border-yellow-400/20 text-yellow-50/80 bg-yellow-500/10"},
|
||||
"warn:": {"icon-[tabler--alert-triangle]", "border-yellow-400/20 text-yellow-50/80 bg-yellow-500/10"},
|
||||
"alert:": {"icon-[tabler--alert-circle]", "border-red-400/20 text-red-50/80 bg-red-500/10"},
|
||||
}
|
||||
|
||||
lowerN := strings.ToLower(n)
|
||||
for prefix, data := range prefixes {
|
||||
if strings.HasPrefix(lowerN, prefix) {
|
||||
return fmt.Sprintf(
|
||||
"<div class='%s %s'><i class='mr-2 text-lg %s'></i><span>%s</span></div>",
|
||||
baseClasses, data.classes, data.icon, strings.TrimPrefix(n, prefix),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("<p class='%s border-gray-400/20 bg-gray-500/10'>%s</p>", baseClasses, n)
|
||||
}
|
||||
|
||||
templ Service(s *ent.Service) {
|
||||
@Base(s.Name) {
|
||||
<section class="flex flex-col justify-center items-center p-2 my-4 mt-8 mb-2 space-y-4 font-bold text-md md:text-md">
|
||||
if s.PotentialScam {
|
||||
<a
|
||||
href="#"
|
||||
target="_blank"
|
||||
class="flex flex-col justify-center items-center px-2 py-2 m-1 space-x-2 text-center text-red-500 rounded border border-red-600 transition duration-300 bg-zinc-900 hover:border-red-600 hover:text-red-600"
|
||||
>
|
||||
<span>
|
||||
<i class="text-xl text-red-500 icon-[tabler--alert-triangle]"></i>
|
||||
<span>POTENTIAL SCAM</span>
|
||||
<i class="text-xl text-red-500 icon-[tabler--alert-triangle]"></i>
|
||||
</span>
|
||||
<span class="text-xs">THIS SERVICE HAS BEEN MARKED AS A POTENTIAL SCAM</span>
|
||||
</a>
|
||||
}
|
||||
if s.Pending {
|
||||
<a
|
||||
href="#"
|
||||
target="_blank"
|
||||
class="flex flex-col justify-center items-center px-2 py-2 m-1 space-x-2 text-center text-yellow-500 rounded border border-yellow-600 transition duration-300 bg-zinc-900 hover:border-yellow-600 hover:text-yellow-600"
|
||||
>
|
||||
<span>
|
||||
<i class="text-xl text-yellow-500 icon-[tabler--alert-triangle]"></i>
|
||||
<span>Pending approval</span>
|
||||
<i class="text-xl text-yellow-500 icon-[tabler--alert-triangle]"></i>
|
||||
</span>
|
||||
<span class="text-xs">This service has not been reviewed</span>
|
||||
</a>
|
||||
}
|
||||
if !s.Pending && !s.Listed {
|
||||
<a
|
||||
href="#"
|
||||
target="_blank"
|
||||
class="flex flex-col justify-center items-center px-2 py-2 m-1 space-x-2 text-center text-red-500 rounded border border-red-600 transition duration-300 bg-zinc-900 hover:border-red-600 hover:text-red-600"
|
||||
>
|
||||
<span>
|
||||
<i class="text-xl text-red-500 icon-[tabler--alert-triangle]"></i>
|
||||
<span>DELISTED</span>
|
||||
<i class="text-xl text-red-500 icon-[tabler--alert-triangle]"></i>
|
||||
</span>
|
||||
<span class="text-xs">This service has been delisted</span>
|
||||
</a>
|
||||
}
|
||||
// Notes are shown at the top of the service page
|
||||
// Notes can have prefix: "alert:", "info:", "warning:" to style them
|
||||
if len(s.Notes) > 0 {
|
||||
for _, note := range s.Notes {
|
||||
if note != "" {
|
||||
@templ.Raw(formatNote(note))
|
||||
}
|
||||
}
|
||||
}
|
||||
// HEADER
|
||||
<header class="flex justify-center items-center space-x-4">
|
||||
<img class="rounded-full size-10 md:size-14 bg-white/25" src={ "/static/images/" + s.Slug + ".jpg" } alt=""/>
|
||||
<span class="flex justify-center items-center">
|
||||
<span class="text-xl font-bold md:text-2xl">{ s.Name }</span>
|
||||
// VERIFIED
|
||||
if s.Verified {
|
||||
<a class="flex justify-center items-center" aria-label="Verified" data-balloon-pos="up" href={ templ.SafeURL(fmt.Sprintf("/static/proofs/%s/proof.txt.asc", s.Name)) }>
|
||||
<i class="ml-2 text-2xl icon-[tabler--rosette-discount-check-filled] text-blue-400/80"></i>
|
||||
</a>
|
||||
}
|
||||
</span>
|
||||
</header>
|
||||
// LINKS
|
||||
<section class="flex flex-wrap justify-center items-center space-x-2">
|
||||
// Website
|
||||
if len(s.Urls) > 0 {
|
||||
<span class="flex">
|
||||
<a
|
||||
class={
|
||||
"flex items-center justify-center px-2 py-1 space-x-1 text-sm text-center text-gray-300 transition duration-300 border border-gray-600 bg-zinc-900 hover:border-lime-600 hover:text-lime-600",
|
||||
templ.KV("rounded-l", s.Referral != ""),
|
||||
templ.KV("rounded", s.Referral == ""),
|
||||
}
|
||||
href={ templ.SafeURL(fmt.Sprintf("%s%s", utils.GetRandomString(s.Urls), s.Referral)) }
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<i class="icon-[tabler--world-www]"></i>
|
||||
<span>Website</span>
|
||||
</a>
|
||||
if s.Referral != "" {
|
||||
<a
|
||||
aria-label="No Referral"
|
||||
data-balloon-pos="up"
|
||||
href={ templ.SafeURL(utils.GetRandomString(s.Urls)) }
|
||||
class="flex justify-center items-center px-1 py-1 text-center text-gray-300 rounded-r border border-gray-600 transition duration-300 md:px-2 bg-zinc-900 hover:border-lime-600 hover:text-lime-600"
|
||||
>
|
||||
<i class="icon-[tabler--link-off]"></i>
|
||||
</a>
|
||||
}
|
||||
</span>
|
||||
}
|
||||
// Tor Onion
|
||||
if len(s.OnionUrls) > 0 {
|
||||
<span class="flex">
|
||||
<a
|
||||
class={
|
||||
"flex items-center justify-center px-2 py-1 space-x-1 text-sm text-center text-purple-600 transition duration-300 border border-purple-900 bg-zinc-900 hover:border-lime-600 hover:text-lime-600",
|
||||
templ.KV("rounded-l", s.Referral != ""),
|
||||
templ.KV("rounded", s.Referral == ""),
|
||||
}
|
||||
href={ templ.SafeURL(fmt.Sprintf("%s%s", utils.GetRandomString(s.OnionUrls), s.Referral)) }
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<i class="icon-[tabler--target]"></i>
|
||||
<span>
|
||||
if len(s.Urls) == 0 {
|
||||
<span>Tor Only</span>
|
||||
} else {
|
||||
<span>Tor</span>
|
||||
}
|
||||
</span>
|
||||
</a>
|
||||
if s.Referral != "" {
|
||||
<a
|
||||
aria-label="No Referral"
|
||||
data-balloon-pos="up"
|
||||
href={ templ.SafeURL(utils.GetRandomString(s.OnionUrls)) }
|
||||
class="flex justify-center items-center px-1 py-1 text-center text-purple-600 rounded-r border border-purple-900 transition duration-300 md:px-2 bg-zinc-900 hover:border-lime-600 hover:text-lime-600"
|
||||
>
|
||||
<i class="icon-[tabler--link-off]"></i>
|
||||
</a>
|
||||
}
|
||||
</span>
|
||||
}
|
||||
// Terms of Service
|
||||
if len(s.TosUrls) > 0 {
|
||||
<a href={ templ.SafeURL(s.TosUrls[0]) } target="_blank" class="flex justify-center items-center px-2 py-0.5 m-1 space-x-2 text-center text-gray-300 rounded border border-gray-600 transition duration-300 bg-zinc-900 hover:border-lime-600 hover:text-lime-600">
|
||||
<i class="icon-[tabler--report-search]"></i>
|
||||
<span>ToS</span>
|
||||
</a>
|
||||
}
|
||||
</section>
|
||||
// "LEAVE A REVIEW": Link to comments section
|
||||
<a aria-label="Discuss this service" data-balloon-pos="up" href="#discuss" class="flex justify-center items-center px-2 py-0.5 space-x-2 text-sm text-center text-gray-400 rounded border border-gray-700 transition duration-300 bg-zinc-900 hover:border-gray-600 hover:text-gray-600">
|
||||
<i class="icon-[tabler--messages]"></i>
|
||||
<span>Leave a review</span>
|
||||
</a>
|
||||
<div class="flex justify-center items-center space-x-2">
|
||||
@partials.ServiceIcons(s)
|
||||
</div>
|
||||
// Description
|
||||
<p class="p-4 max-w-lg text-sm rounded-lg border md:text-base border-white/20 bg-gray-500/10">
|
||||
@templ.Raw(s.Description)
|
||||
</p>
|
||||
</section>
|
||||
// KYC LEVEL
|
||||
<section class="flex justify-center items-center px-2">
|
||||
<div
|
||||
class={
|
||||
"flex flex-col justify-center max-w-lg p-4 text-sm border rounded-lg md:text-base",
|
||||
templ.KV("border-green-500/20 bg-green-500/10", s.KycLevel == 0),
|
||||
templ.KV("border-lime-300/40 bg-lime-300/10", s.KycLevel == 1),
|
||||
templ.KV("border-amber-700/40 bg-amber-600/20", s.KycLevel == 2),
|
||||
templ.KV("border-red-600/40 bg-red-600/20", s.KycLevel == 3),
|
||||
}
|
||||
>
|
||||
// KYC LEVEL TITLE
|
||||
<h2 class={ "flex items-center space-x-2 text-lg font-bold" }>
|
||||
<i
|
||||
class={
|
||||
"ti",
|
||||
templ.KV("text-green-600 icon-[tabler--circle-check-filled]", s.KycLevel == 0),
|
||||
templ.KV("text-lime-400/70 icon-[tabler--circle-check]", s.KycLevel == 1),
|
||||
templ.KV("text-amber-600 icon-[tabler--alert-triangle-filled]", s.KycLevel == 2),
|
||||
templ.KV("text-red-600 icon-[tabler--alert-octagon-filled]", s.KycLevel == 3),
|
||||
}
|
||||
></i>
|
||||
<span>KYC LEVEL <b>{ fmt.Sprintf("%d", s.KycLevel) }</b> </span>
|
||||
</h2>
|
||||
// KYC LEVEL DESCRIPTION
|
||||
<p class="mt-2 text-sm">
|
||||
switch s.KycLevel {
|
||||
case 0:
|
||||
The exchange ToS <b class="font-bold">do not mention</b> that it will ever
|
||||
request the user for a KYC verification.
|
||||
case 1:
|
||||
KYC is <b class="font-bold">not mentioned</b>, but this service
|
||||
<b class="font-bold">reserves the right to share data</b> with
|
||||
representatives of the authorities, block funds or reject transactions.
|
||||
case 2:
|
||||
The exchange
|
||||
<b class="font-bold">may request KYC from any user at any time</b>,
|
||||
typically triggered by an automated flag system, leading to a temporary
|
||||
block of funds.
|
||||
case 3:
|
||||
KYC is <b class="font-bold">mandatory to use some features</b>. A non-KYCed
|
||||
user can be required to verify their identity at any time or any moment for
|
||||
any reason.
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
// Comments
|
||||
if len(s.Comments) > 0 {
|
||||
<section class="flex flex-col justify-center items-center p-4">
|
||||
<div class="mb-5 space-y-1.5 max-w-lg">
|
||||
for _, comment := range s.Comments {
|
||||
if comment != "" {
|
||||
@templ.Raw(formatNote(comment))
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
// Attributes
|
||||
if len(s.Edges.Attributes) > 0 {
|
||||
<section class="flex flex-col justify-center items-center p-4">
|
||||
<div class="grid grid-cols-1 auto-cols-max gap-2 mt-2 md:grid-cols-2">
|
||||
for _, attr := range s.Edges.Attributes {
|
||||
@partials.AttributeLine(attr)
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
// Support Contact Methods
|
||||
if len(s.Support) > 0 {
|
||||
<section id="contact" class="flex flex-col justify-center items-center p-4">
|
||||
<ul class="flex items-center justify-center gap-2 flex-wrap text-sm [&>li>a]:p-2 [&>li>a]:rounded [&>li>a]:bg-white/10 hover:[&>li>a]:bg-white/20 [&>li>a]:transition [&>li>a]:duration-200">
|
||||
for _, sp := range s.Support {
|
||||
<li class="text-center">
|
||||
<a class="flex justify-center items-center space-x-2" href={ templ.SafeURL(sp.Link) }>
|
||||
// Icons used in this item are limited to icons declared in src/frontend/templates/01-extra-icons.html
|
||||
// TODO: Create key value map, for icons names and fallback if not found, to replace the extra-icons.html
|
||||
<i class={ fmt.Sprintf("icon-[tabler--%s]", sp.Icon) }></i>
|
||||
<span>{ sp.Text }</span>
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</section>
|
||||
}
|
||||
<div class="my-2 w-full border-t-2 border-opacity-50 border-dashed border-t-lime-400/10"></div>
|
||||
// Terms of Service AI Automated reviews
|
||||
<section class="flex flex-col justify-center items-center p-4" id="tos">
|
||||
<a href="/about#tos-checker" class="text-xl font-bold">
|
||||
<i class="icon-[tabler--calendar-cog]"></i>
|
||||
<span>ToS Review</span>
|
||||
<span class="text-xs text-white/30">?</span>
|
||||
</a>
|
||||
<p class="max-w-sm text-xs text-center text-gray-500 text-opacity-75">Automated, ai-driven monthly ToS reviews.</p>
|
||||
if len(s.TosUrls) == 0 {
|
||||
<p class="mt-2 max-w-md font-bold text-center text-amber-400 text-opacity-75 text-md">This service has no ToS.</p>
|
||||
} else if len(s.TosReviews) == 0 {
|
||||
<p class="mt-2 max-w-md font-bold text-center text-amber-400 text-opacity-75 text-md">No ToS reviews for this service (yet).</p>
|
||||
} else {
|
||||
<p class="mt-1 max-w-sm text-xs text-center text-gray-600 text-opacity-75">Last Check: { s.LastTosReview.Format("2006-01-02") }</p>
|
||||
<div class="max-w-lg">
|
||||
for _, tr := range s.TosReviews {
|
||||
if tr.Warning {
|
||||
<div
|
||||
class={
|
||||
"px-3 py-2 mt-2 border rounded-md w-full",
|
||||
templ.KV("border-amber-900 bg-amber-900/30", tr.Warning),
|
||||
templ.KV("border-blue-900 bg-blue-900/30", !tr.Warning),
|
||||
}
|
||||
>
|
||||
<h3 class="text-sm font-bold uppercase">{ tr.Title }</h3>
|
||||
<p class="my-1.5 text-sm">{ tr.Details }</p>
|
||||
if tr.Section != "" {
|
||||
<p class="text-xs text-gray-400 text-opacity-40">ToS section: <span>{ tr.Section }</span></p>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</section>
|
||||
<div class="my-2 w-full border-t-2 border-opacity-50 border-dashed border-t-lime-400/10"></div>
|
||||
<!-- Comments -->
|
||||
<section class="flex flex-col justify-center items-center p-4 mb-16" id="discuss">
|
||||
<a href="/about#comments" target="_blank" class="text-xl font-bold">
|
||||
<i class="inline-block icon-[tabler--messages]"></i>
|
||||
<span>Comments</span>
|
||||
<span class="text-xs text-white/30">?</span>
|
||||
</a>
|
||||
<p class="pb-4 mt-1 max-w-sm text-xs text-center text-gray-500 text-opacity-75">
|
||||
Alghough comments are <a class="underline hover:text-gray-400" href="/about#comment-moderation">moderated</a>, beware of fake reviews. Always do your own research.
|
||||
</p>
|
||||
<!-- Div where comentario will set the client-->
|
||||
<div id="comment-section" class="mx-2 w-full max-w-xl break-all sm:mx-6">
|
||||
<comentario-comments></comentario-comments>
|
||||
<noscript>
|
||||
<p class="mb-2 font-bold text-center text-yellow-300">
|
||||
You can enable JavaScript to see and use comments here. It just will load a 20kb open-source script to
|
||||
interact with our instance of Comentario.
|
||||
The source code is available on <a
|
||||
target="_blank"
|
||||
class="underline"
|
||||
href="https://gitlab.com/commento/commento"
|
||||
>Gitlab</a>.
|
||||
</p>
|
||||
</noscript>
|
||||
</div>
|
||||
</section>
|
||||
// Comentario JS script
|
||||
<script defer src="https://comments.kycnot.me/comentario.js"></script>
|
||||
}
|
||||
}
|
33
src/frontend/templates/service_pending_list.templ
Normal file
@ -0,0 +1,33 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"kycnot.me/frontend/templates/partials"
|
||||
"kycnot.me/internal/ent"
|
||||
)
|
||||
|
||||
templ ServicePendingList(pendingServices []*ent.Service) {
|
||||
@Base("Pending Services") {
|
||||
<main class="py-2 mt-4 text-lime-500">
|
||||
<div class="mb-2 text-center bg-transparent md:grid">
|
||||
<p class="font-mono text-2xl font-bold uppercase">
|
||||
<i class="icon-[tabler--hourglass-high] text-lg"></i>
|
||||
Pending Services
|
||||
<i class="icon-[tabler--hourglass-high] text-lg"></i>
|
||||
</p>
|
||||
<p class="mt-1 text-sm">The following services have been requested and are pending for review.</p>
|
||||
</div>
|
||||
</main>
|
||||
<!-- Services list -->
|
||||
<section class="flex justify-center items-center px-3 pb-12 mt-4">
|
||||
<div class="grid grid-cols-1 gap-3 max-w-6xl lg:grid-cols-3">
|
||||
if len(pendingServices) > 0 {
|
||||
for _, ps := range pendingServices {
|
||||
@partials.ServiceCard(ps)
|
||||
}
|
||||
} else {
|
||||
<h2 class="my-8 text-xl font-bold text-center">No pending services.</h2>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
}
|
330
src/frontend/templates/service_request_form.templ
Normal file
@ -0,0 +1,330 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"kycnot.me/internal/ent"
|
||||
"kycnot.me/internal/ent/attribute"
|
||||
"kycnot.me/internal/models"
|
||||
)
|
||||
|
||||
func getAttributeColor(t attribute.Rating) string {
|
||||
switch t {
|
||||
case attribute.RatingBad:
|
||||
return "text-red-400/80"
|
||||
case attribute.RatingInfo:
|
||||
return "text-blue-400/80"
|
||||
case attribute.RatingGood:
|
||||
return "text-green-400/80"
|
||||
case attribute.RatingWarn:
|
||||
return "text-yellow-400/80"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
templ RequestForm(opts *models.BaseOpts, attributes []*ent.Attribute) {
|
||||
@Base("Request") {
|
||||
if opts.Error != "" {
|
||||
<div class="flex justify-center items-center">
|
||||
<p class="px-2 py-2 font-bold text-center rounded-lg bg-red-500/70 text-md text-neutral-100">
|
||||
{ opts.Error }
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
if opts.Message != "" {
|
||||
<div class="flex justify-center items-center">
|
||||
<p class="px-2 py-2 font-bold text-center rounded-lg text-md bg-blue-500/70 text-neutral-100">
|
||||
{ opts.Message }
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
<section class="flex flex-col items-center py-8 w-full">
|
||||
<h2 class="text-2xl font-bold">Request a service</h2>
|
||||
<small class="opacity-70">*This form requires JavaScript, <a class="text-lime-600" href="/about#request">read more here</a>.</small>
|
||||
<form action="/request" method="POST" class="my-6 space-y-4 max-w-lg font-mono">
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="type">Service Type</label>
|
||||
<select
|
||||
name="type"
|
||||
id="type"
|
||||
required
|
||||
class="p-2 text-white uppercase bg-opacity-30 rounded-lg border bg-zinc-900 border-white/30"
|
||||
>
|
||||
<option selected value="exchange">exchange</option>
|
||||
<option value="service">service</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="category-container" class="flex flex-col">
|
||||
<label class="font-bold" for="category">Service Category</label>
|
||||
<select
|
||||
name="category"
|
||||
id="category"
|
||||
required
|
||||
class="p-2 text-white uppercase bg-opacity-30 rounded-lg border bg-zinc-900 border-white/30"
|
||||
>
|
||||
<option value="aggregator">aggregator</option>
|
||||
<option value="atm">physical atm</option>
|
||||
<option value="cloud">cloud storage</option>
|
||||
<option value="email">email</option>
|
||||
<option value="goods">goods</option>
|
||||
<option value="hosting">hosting / domains</option>
|
||||
<option value="market">market</option>
|
||||
<option value="proxy store">proxy store</option>
|
||||
<option value="sms">sms / phone number</option>
|
||||
<option value="tools">tools</option>
|
||||
<option value="vpn">vpn</option>
|
||||
<option value="ai">ai</option>
|
||||
<option value="vps">server hosting (vps)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="name">Service Name</label>
|
||||
<input
|
||||
class="p-2 text-white bg-opacity-30 rounded-lg border placeholder-white/30 bg-zinc-900 border-white/30"
|
||||
placeholder="Awesome exchange"
|
||||
type="text"
|
||||
name="name"
|
||||
id="name"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="description">Description</label>
|
||||
<textarea
|
||||
class="p-2 font-mono text-white bg-opacity-30 rounded-lg border placeholder-white/30 bg-zinc-900 border-white/30"
|
||||
name="description"
|
||||
id="description"
|
||||
placeholder="concise description about what the service is. max 500 characters."
|
||||
cols="30"
|
||||
rows="5"
|
||||
required
|
||||
minlength="60"
|
||||
maxlength="500"
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="urls">Service URL(s)</label>
|
||||
<small class="text-white/30">*If more than one, separate with commas.</small>
|
||||
<input
|
||||
class="p-2 text-white bg-opacity-30 rounded-lg border placeholder-white/30 bg-zinc-900 border-white/30"
|
||||
type="text"
|
||||
name="urls"
|
||||
id="urls"
|
||||
required
|
||||
placeholder="https://example.com"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="logo_url">Logo URL</label>
|
||||
<input
|
||||
class="p-2 text-white bg-opacity-30 rounded-lg border placeholder-white/30 bg-zinc-900 border-white/30"
|
||||
type="text"
|
||||
name="logo_url"
|
||||
id="logo_url"
|
||||
placeholder="https://i.imgur.com/wwwHfCN.jpeg"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="tos_urls">ToS URL(s)</label>
|
||||
<small class="text-white/30">*If more than one, separate with commas.</small>
|
||||
<input
|
||||
class="p-2 text-white bg-opacity-30 rounded-lg border placeholder-white/30 bg-zinc-900 border-white/30"
|
||||
type="text"
|
||||
name="tos_urls"
|
||||
id="tos_urls"
|
||||
required
|
||||
placeholder="https://example.com/terms"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="onion_urls">Tor Onion URL(s)</label>
|
||||
<small class="text-white/30">*If more than one, separate with commas.</small>
|
||||
<input
|
||||
class="p-2 text-white bg-opacity-30 rounded-lg border placeholder-white/30 bg-zinc-900 border-white/30"
|
||||
type="text"
|
||||
name="onion_urls"
|
||||
id="onion_urls"
|
||||
placeholder="http://zbiowkw...onion"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<label class="font-bold" for="tags">Keywords</label>
|
||||
<small class="text-white/30">*If more than one, separate with commas.</small>
|
||||
<input
|
||||
class="p-2 text-white bg-opacity-30 rounded-lg border placeholder-white/30 bg-zinc-900 border-white/30"
|
||||
type="text"
|
||||
name="tags"
|
||||
id="tags"
|
||||
required
|
||||
placeholder="private,p2p, fast"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center items-center pt-4 space-x-2">
|
||||
<h3 class="mb-2 text-xl">Accepted currencies</h3>
|
||||
<div class="flex space-x-4">
|
||||
<span class="flex flex-col justify-center items-center">
|
||||
<label class="text-xs uppercase" for="btc">BITCOIN</label>
|
||||
<input
|
||||
class="text-lime-500 bg-opacity-30 rounded-full border-lime-500 appearance-none outline-none bg-zinc-900 focus:ring-0"
|
||||
type="checkbox"
|
||||
name="btc"
|
||||
id="btc"
|
||||
/>
|
||||
</span>
|
||||
<span class="flex flex-col justify-center items-center">
|
||||
<label class="text-xs uppercase" for="xmr">MONERO</label>
|
||||
<input
|
||||
class="text-lime-500 bg-opacity-30 rounded-full border-lime-500 appearance-none outline-none bg-zinc-900 focus:ring-0"
|
||||
type="checkbox"
|
||||
name="xmr"
|
||||
id="xmr"
|
||||
/>
|
||||
</span>
|
||||
<span class="flex flex-col justify-center items-center">
|
||||
<label class="text-xs uppercase" for="ln">LIGHTNING</label>
|
||||
<input
|
||||
class="text-lime-500 bg-opacity-30 rounded-full border-lime-500 appearance-none outline-none bg-zinc-900 focus:ring-0"
|
||||
type="checkbox"
|
||||
name="ln"
|
||||
id="ln"
|
||||
/>
|
||||
</span>
|
||||
<span class="flex flex-col justify-center items-center">
|
||||
<label class="text-xs uppercase" for="fiat">FIAT</label>
|
||||
<input
|
||||
class="text-lime-500 bg-opacity-30 rounded-full border-lime-500 appearance-none outline-none bg-zinc-900 focus:ring-0"
|
||||
type="checkbox"
|
||||
name="fiat"
|
||||
id="fiat"
|
||||
/>
|
||||
</span>
|
||||
<span class="flex flex-col justify-center items-center">
|
||||
<label class="text-xs uppercase" for="cash">CASH</label>
|
||||
<input
|
||||
class="text-lime-500 bg-opacity-30 rounded-full border-lime-500 appearance-none outline-none bg-zinc-900 focus:ring-0"
|
||||
type="checkbox"
|
||||
name="cash"
|
||||
id="cash"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
<h3 class="font-bold">KYC Level</h3>
|
||||
<label class="flex flex-row items-center p-2 rounded-lg border border-white/10" for="kyclevel0">
|
||||
<input type="radio" name="kyc_level" id="kyclevel0" value="0"/>
|
||||
<p class="ml-3">
|
||||
<b class="text-lime-400">Level 0</b>: No KYC ever. The ToS do not mention nor enforce
|
||||
any KYC/AML verification.
|
||||
</p>
|
||||
</label>
|
||||
<label class="flex flex-row items-center p-2 rounded-lg border border-white/10" for="kyclevel1">
|
||||
<input type="radio" name="kyc_level" id="kyclevel1" value="1"/>
|
||||
<p class="ml-3">
|
||||
<b class="text-lime-400">Level 1</b>: No KYC/AML procedures are mentioned as such,
|
||||
however the service reserves the right to share acquired data with authorities, block funds or
|
||||
reject transactions.
|
||||
</p>
|
||||
</label>
|
||||
<label class="flex flex-row items-center p-2 rounded-lg border border-white/10" for="kyclevel2">
|
||||
<input type="radio" name="kyc_level" id="kyclevel2" value="2" checked/>
|
||||
<p class="ml-3">
|
||||
<b class="text-lime-400">Level 2</b>: KYC is not mandatory, but the service can require
|
||||
KYC from any user at any time, and it may block funds. This could occur, for example, if a
|
||||
transaction is flagged suspicious.
|
||||
</p>
|
||||
</label>
|
||||
<label class="flex flex-row items-center p-2 rounded-lg border border-white/10" for="kyclevel3">
|
||||
<input type="radio" name="kyc_level" id="kyclevel3" value="3"/>
|
||||
<p class="ml-3">
|
||||
<b class="text-lime-400">Level 3</b>: KYC is mandatory to use certain features of the
|
||||
platform. Non-KYC users can be asked to verify their identity at any time, for any reason and may
|
||||
have their service restricted or revoked.
|
||||
</p>
|
||||
</label>
|
||||
</div>
|
||||
<h3 class="font-bold">Attributes</h3>
|
||||
<small class="text-white/50">* Scrollable. You must check at least 3</small>
|
||||
<div class="overflow-scroll p-4 mx-4 mb-4 space-y-2 max-w-lg h-52 rounded-lg border border-white/10">
|
||||
for _, attr := range attributes {
|
||||
<span class="block p-1 border-b border-white/10">
|
||||
<input type="checkbox" id={ attr.ID } name="attributes" value={ attr.ID }/>
|
||||
<label class={ getAttributeColor(attr.Rating) + " ml-1" } for={ attr.ID }>{ attr.Title }</label>
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
<noscript>
|
||||
<p class="my-2 font-bold text-yellow-500 uppercase">
|
||||
You need to enable JavaScript to complete this form.
|
||||
</p>
|
||||
</noscript>
|
||||
<div
|
||||
id="start-pow"
|
||||
class="flex justify-center items-center px-4 py-2 mt-2 mb-4 space-x-2 font-bold uppercase bg-blue-900 rounded-lg cursor-pointer"
|
||||
>
|
||||
<input type="text" name="pow-nonce" id="pow-nonce" hidden required value=""/>
|
||||
<input type="text" name="pow-id" id="pow-id" hidden required value=""/>
|
||||
<svg
|
||||
id="pow-spinner"
|
||||
class="hidden text-white fill-white"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<style>
|
||||
.spinner_ZCsl {
|
||||
animation: spinner_qV4G 1.2s cubic-bezier(0.52, .6, .25, .99) infinite
|
||||
}
|
||||
|
||||
.spinner_gaIW {
|
||||
animation-delay: .6s
|
||||
}
|
||||
|
||||
@keyframes spinner_qV4G {
|
||||
0% {
|
||||
r: 0;
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
100% {
|
||||
r: 11px;
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<circle class="spinner_ZCsl" cx="12" cy="12" r="0"></circle>
|
||||
<circle class="spinner_ZCsl spinner_gaIW" cx="12" cy="12" r="0"></circle>
|
||||
</svg>
|
||||
<span id="pow-text">🧠 I'm Human</span>
|
||||
</div>
|
||||
<button
|
||||
id="submit-btn"
|
||||
class="hidden px-4 py-2 my-4 space-x-2 w-full font-bold uppercase bg-lime-900 rounded-lg cursor-pointer"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</form>
|
||||
</section>
|
||||
<script src="/static/js/pow.js"></script>
|
||||
<script>
|
||||
// Toggle category select based on type select
|
||||
document.addEventListener('DOMContentLoaded', (event) => {
|
||||
const typeSelect = document.getElementById('type');
|
||||
const categoryDiv = document.getElementById('category-container');
|
||||
|
||||
function toggleCategory() {
|
||||
if (typeSelect.value === 'service') {
|
||||
categoryDiv.style.display = 'flex'; // Show
|
||||
} else {
|
||||
categoryDiv.style.display = 'none'; // Hide
|
||||
}
|
||||
}
|
||||
// Initial toggle based on the preselected option
|
||||
toggleCategory();
|
||||
// Add change event listener to the type select element
|
||||
typeSelect.addEventListener('change', toggleCategory);
|
||||
});
|
||||
</script>
|
||||
}
|
||||
}
|
77
src/go.mod
@ -1,72 +1,77 @@
|
||||
module pluja.dev/kycnot.me
|
||||
module kycnot.me
|
||||
|
||||
go 1.22
|
||||
|
||||
toolchain go1.22.1
|
||||
go 1.23.1
|
||||
|
||||
require (
|
||||
github.com/allegro/bigcache/v3 v3.1.0
|
||||
github.com/chai2010/webp v1.1.1
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/iris-contrib/middleware/cors v0.0.0-20240502084239-34f27409ce72
|
||||
entgo.io/ent v0.14.1
|
||||
github.com/a-h/templ v0.2.793
|
||||
github.com/dgraph-io/ristretto v0.2.0
|
||||
github.com/go-sql-driver/mysql v1.8.1
|
||||
github.com/gosimple/slug v1.14.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/kataras/iris/v12 v12.2.11
|
||||
github.com/pluja/pocketbase v0.0.61
|
||||
github.com/rs/zerolog v1.32.0
|
||||
github.com/sashabaranov/go-openai v1.24.0
|
||||
golang.org/x/image v0.16.0
|
||||
golang.org/x/net v0.25.0
|
||||
github.com/microcosm-cc/bluemonday v1.0.26
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
github.com/phuslu/log v1.0.113
|
||||
github.com/samber/lo v1.47.0
|
||||
github.com/sashabaranov/go-openai v1.35.7
|
||||
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0
|
||||
golang.org/x/image v0.23.0
|
||||
)
|
||||
|
||||
require (
|
||||
ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 // indirect
|
||||
github.com/CloudyKit/jet/v6 v6.2.0 // indirect
|
||||
github.com/Joker/jade v1.1.3 // indirect
|
||||
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect
|
||||
github.com/SierraSoftworks/multicast/v2 v2.0.0 // indirect
|
||||
github.com/agext/levenshtein v1.2.1 // indirect
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 // indirect
|
||||
github.com/duke-git/lancet/v2 v2.3.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/flosch/pongo2/v4 v4.0.2 // indirect
|
||||
github.com/go-resty/resty/v2 v2.13.1 // indirect
|
||||
github.com/go-openapi/inflect v0.19.0 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2 // indirect
|
||||
github.com/gorilla/css v1.0.1 // indirect
|
||||
github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
github.com/gosimple/unidecode v1.0.1 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.13.0 // indirect
|
||||
github.com/iris-contrib/schema v0.0.6 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/kataras/blocks v0.0.8 // indirect
|
||||
github.com/kataras/golog v0.1.12 // indirect
|
||||
github.com/kataras/golog v0.1.11 // indirect
|
||||
github.com/kataras/pio v0.0.13 // indirect
|
||||
github.com/kataras/sitemap v0.0.6 // indirect
|
||||
github.com/kataras/tunnel v0.0.4 // indirect
|
||||
github.com/klauspost/compress v1.17.8 // indirect
|
||||
github.com/klauspost/compress v1.17.7 // indirect
|
||||
github.com/mailgun/raymond/v2 v2.0.48 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/microcosm-cc/bluemonday v1.0.26 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/schollz/closestmatch v2.1.0+incompatible // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/tdewolff/minify/v2 v2.20.21 // indirect
|
||||
github.com/tdewolff/parse/v2 v2.7.14 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/tdewolff/minify/v2 v2.20.19 // indirect
|
||||
github.com/tdewolff/parse/v2 v2.7.12 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
github.com/yosssi/ace v0.0.5 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
github.com/zclconf/go-cty v1.8.0 // indirect
|
||||
golang.org/x/crypto v0.26.0 // indirect
|
||||
golang.org/x/mod v0.20.0 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/sys v0.23.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
336
src/go.sum
@ -1,89 +1,44 @@
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
|
||||
ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43 h1:GwdJbXydHCYPedeeLt4x/lrlIISQ4JTH1mRWuE5ZZ14=
|
||||
ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43/go.mod h1:uj3pm+hUTVN/X5yfdBexHlZv+1Xu5u5ZbZx7+CDavNU=
|
||||
entgo.io/ent v0.14.1 h1:fUERL506Pqr92EPHJqr8EYxbPioflJo6PudkrEA8a/s=
|
||||
entgo.io/ent v0.14.1/go.mod h1:MH6XLG0KXpkcDQhKiHfANZSzR55TJyPL5IGNpI8wpco=
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c=
|
||||
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
|
||||
github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME=
|
||||
github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc=
|
||||
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
||||
github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk=
|
||||
github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM=
|
||||
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0=
|
||||
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM=
|
||||
github.com/SierraSoftworks/multicast/v2 v2.0.0 h1:0mN2KN5VLc+xEnbvrXOlRTqoz4bzp6MIvp1vwnwkNGo=
|
||||
github.com/SierraSoftworks/multicast/v2 v2.0.0/go.mod h1:+4a2KDy5y3Bf/K5O++7SNBlQ2qZrwj9T3dEVTxwM2K8=
|
||||
github.com/a-h/templ v0.2.793 h1:Io+/ocnfGWYO4VHdR0zBbf39PQlnzVCVVD+wEEs6/qY=
|
||||
github.com/a-h/templ v0.2.793/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w=
|
||||
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
|
||||
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||
github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk=
|
||||
github.com/allegro/bigcache/v3 v3.1.0/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-sdk-go v1.48.16 h1:mcj2/9J/MJ55Dov+ocMevhR8Jv6jW/fAxbrn4a1JFc8=
|
||||
github.com/aws/aws-sdk-go v1.48.16/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
github.com/aws/aws-sdk-go-v2 v1.24.0 h1:890+mqQ+hTpNuw0gGP6/4akolQkSToDJgHfQE7AwGuk=
|
||||
github.com/aws/aws-sdk-go-v2 v1.24.0/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4/go.mod h1:usURWEKSNNAcAZuzRn/9ZYPT8aZQkR7xcCtunK/LkJo=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.26.1 h1:z6DqMxclFGL3Zfo+4Q0rLnAZ6yVkzCRxhRMsiRQnD1o=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.26.1/go.mod h1:ZB+CuKHRbb5v5F0oJtGdhFTelmrxd4iWO1lf0rQwSAg=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.12 h1:v/WgB8NxprNvr5inKIiVVrXPuuTegM+K8nncFkr1usU=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.12/go.mod h1:X21k0FjEJe+/pauud82HYiQbEr9jRKY3kXEIQ4hXeTQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 h1:w98BT5w+ao1/r5sUuiH6JkVzjowOKeOJRHERyy1vh58=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10/go.mod h1:K2WGI7vUvkIv1HoNbfBA1bvIZ+9kL3YVmWxeKuLQsiw=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.7 h1:FnLf60PtjXp8ZOzQfhJVsqF0OtYKQZWQfqOLshh8YXg=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.7/go.mod h1:tDVvl8hyU6E9B8TrnNrZQEVkQlB8hjJwcgpPhgtlnNg=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 h1:v+HbZaCGmOwnTTVS86Fleq0vPzOd7tnJGbFhP0stNLs=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9/go.mod h1:Xjqy+Nyj7VDLBtCMkQYOw1QYfAEZCVLrfI0ezve8wd4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 h1:N94sVhRACtXyVcjXxrwK1SKFIJrA9pOJ5yu2eSHnmls=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9/go.mod h1:hqamLz7g1/4EJP+GH5NBhcUMLjW+gKLQabgyz6/7WAU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 h1:ugD6qzjYtB7zM5PN/ZIeaAIyefPaD82G8+SJopgvUpw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9/go.mod h1:YD0aYBWCrPENpHolhKw2XDlTIWae2GKXT1T4o6N6hiM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 h1:/90OR2XbSYfXucBMJ4U14wrjlfleq/0SB6dZDPncgmo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9/go.mod h1:dN/Of9/fNZet7UrQQ6kTDo/VSwKPIq94vjlU16bRARc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 h1:Nf2sHxjMJR8CSImIVCONRi4g0Su3J+TSTbS7G0pUeMU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9/go.mod h1:idky4TER38YIjr2cADF1/ugFMKvZV7p//pVeV5LZbF0=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 h1:iEAeF6YC3l4FzlJPP9H3Ko1TXpdjdqWffxXjp8SY6uk=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9/go.mod h1:kjsXoK23q9Z/tLBrckZLLyvjhZoS+AGrzqzUfEClvMM=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5 h1:Keso8lIOS+IzI2MkPZyK6G0LYcK3My2LQ+T5bxghEAY=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5/go.mod h1:vADO6Jn+Rq4nDtfwNjhgR84qkZwiC6FqCaXdw/kYwjA=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 h1:ldSFWz9tEHAwHNmjx2Cvy1MjP5/L9kNoR0skc6wyOOM=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5/go.mod h1:CaFfXLYL376jgbP7VKC96uFcU8Rlavak0UlAwk1Dlhc=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsYYwrwnd5fIvgEKkfZFNM=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5/go.mod h1:W+nd4wWDVkSUIox9bacmkBP5NMFQeTJ/xqNabpzSR38=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 h1:5UYvv8JUvllZsRnfrcMQ+hJ9jNICmcgKPAO1CER25Wg=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.26.5/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU=
|
||||
github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM=
|
||||
github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/chai2010/webp v1.1.1 h1:jTRmEccAJ4MGrhFOrPMpNGIJ/eybIgwKpcACsrTEapk=
|
||||
github.com/chai2010/webp v1.1.1/go.mod h1:0XVwvZWdjjdxpUEIf7b9g9VkHFnInUSYujwqTLEuldU=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8=
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
|
||||
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 h1:C7t6eeMaEQVy6e8CarIhscYQlNmw5e3G36y7l7Y21Ao=
|
||||
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0/go.mod h1:56wL82FO0bfMU5RvfXoIwSOP2ggqqxT+tAfNEIyxuHw=
|
||||
github.com/duke-git/lancet/v2 v2.2.9 h1:ik02ZrFg/OU0lduLfmNqo73mAhpY2a3Fm1RUFcoEtqk=
|
||||
github.com/duke-git/lancet/v2 v2.2.9/go.mod h1:zGa2R4xswg6EG9I6WnyubDbFO/+A/RROxIbXcwryTsc=
|
||||
github.com/duke-git/lancet/v2 v2.3.1 h1:cYZHQp57CZKP41EFkV/7TGbUrmhjaPMI5vi3Q+9KJNo=
|
||||
github.com/duke-git/lancet/v2 v2.3.1/go.mod h1:zGa2R4xswg6EG9I6WnyubDbFO/+A/RROxIbXcwryTsc=
|
||||
github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE=
|
||||
github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU=
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
@ -92,77 +47,51 @@ github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw=
|
||||
github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||
github.com/ganigeorgiev/fexpr v0.4.0 h1:ojitI+VMNZX/odeNL1x3RzTTE8qAIVvnSSYPNAnQFDI=
|
||||
github.com/ganigeorgiev/fexpr v0.4.0/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
|
||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
|
||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew=
|
||||
github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8=
|
||||
github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
|
||||
github.com/go-resty/resty/v2 v2.13.1 h1:x+LHXBI2nMB1vqndymf26quycC4aggYJ7DECYbiz03g=
|
||||
github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96ORAI6Q7d+0=
|
||||
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
|
||||
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
|
||||
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=
|
||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47 h1:k4Tw0nt6lwro3Uin8eqoET7MDA4JnT8YgbCjc/g5E3k=
|
||||
github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
|
||||
github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2 h1:yEt5djSYb4iNtmV9iJGVday+i4e9u6Mrn5iP64HH5QM=
|
||||
github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 h1:4gjrh/PN2MuWCCElk8/I4OCKRKWCCo2zEct3VKCbibU=
|
||||
github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
|
||||
github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
|
||||
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
||||
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
||||
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
||||
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/gosimple/slug v1.14.0 h1:RtTL/71mJNDfpUbCOmnf/XFkzKRtD6wL6Uy+3akm4Es=
|
||||
github.com/gosimple/slug v1.14.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
|
||||
github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o=
|
||||
github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
|
||||
github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc=
|
||||
github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=
|
||||
github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
|
||||
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
|
||||
github.com/iris-contrib/httpexpect/v2 v2.15.2 h1:T9THsdP1woyAqKHwjkEsbCnMefsAFvk8iJJKokcJ3Go=
|
||||
github.com/iris-contrib/httpexpect/v2 v2.15.2/go.mod h1:JLDgIqnFy5loDSUv1OA2j0mb6p/rDhiCqigP22Uq9xE=
|
||||
github.com/iris-contrib/middleware/cors v0.0.0-20240111010557-e34016a4d6ee h1:srr0HUvI9IAximtqxhF0+WSy9cv9Dd5YlH8RMEkHtsw=
|
||||
github.com/iris-contrib/middleware/cors v0.0.0-20240111010557-e34016a4d6ee/go.mod h1:hAsE+pfCAz1M2cCfsEolTmaBwHCyzchRFyCk5I1+kDo=
|
||||
github.com/iris-contrib/middleware/cors v0.0.0-20240502084239-34f27409ce72 h1:BuEwEv6gPS9pSX0+O5FIxxKUoRziXBFdWI1S4ivKQtY=
|
||||
github.com/iris-contrib/middleware/cors v0.0.0-20240502084239-34f27409ce72/go.mod h1:DQJ0KlNPppOfMC+0x0ADeFQk0WmQMVU9rJQzFY4nUfA=
|
||||
github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw=
|
||||
github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kataras/blocks v0.0.8 h1:MrpVhoFTCR2v1iOOfGng5VJSILKeZZI+7NGfxEh3SUM=
|
||||
github.com/kataras/blocks v0.0.8/go.mod h1:9Jm5zx6BB+06NwA+OhTbHW1xkMOYxahnqTN5DveZ2Yg=
|
||||
github.com/kataras/golog v0.1.11 h1:dGkcCVsIpqiAMWTlebn/ZULHxFvfG4K43LF1cNWSh20=
|
||||
github.com/kataras/golog v0.1.11/go.mod h1:mAkt1vbPowFUuUGvexyQ5NFW6djEgGyxQBIARJ0AH4A=
|
||||
github.com/kataras/golog v0.1.12 h1:Bu7I/G4ilJlbfzjmU39O9N+2uO1pBcMK045fzZ4ytNg=
|
||||
github.com/kataras/golog v0.1.12/go.mod h1:wrGSbOiBqbQSQznleVNX4epWM8rl9SJ/rmEacl0yqy4=
|
||||
github.com/kataras/iris/v12 v12.2.10 h1:rEJVM7qMoyhv8wpgkA1yGxibFcONE0jkJ70LFLibTAA=
|
||||
github.com/kataras/iris/v12 v12.2.10/go.mod h1:z4+E+kLMqZ7U4WtDsYfFnG7BjMTXLkdzMAXLVMLnMNs=
|
||||
github.com/kataras/iris/v12 v12.2.11 h1:sGgo43rMPfzDft8rjVhPs6L3qDJy3TbBrMD/zGL1pzk=
|
||||
github.com/kataras/iris/v12 v12.2.11/go.mod h1:uMAeX8OqG9vqdhyrIPv8Lajo/wXTtAF43wchP9WHt2w=
|
||||
github.com/kataras/pio v0.0.13 h1:x0rXVX0fviDTXOOLOmr4MUxOabu1InVSTu5itF8CXCM=
|
||||
@ -171,90 +100,72 @@ github.com/kataras/sitemap v0.0.6 h1:w71CRMMKYMJh6LR2wTgnk5hSgjVNB9KL60n5e2KHvLY
|
||||
github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4=
|
||||
github.com/kataras/tunnel v0.0.4 h1:sCAqWuJV7nPzGrlb0os3j49lk2JhILT0rID38NHNLpA=
|
||||
github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
|
||||
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
|
||||
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61 h1:FwuzbVh87iLiUQj1+uQUsuw9x5t9m5n5g7rG7o4svW4=
|
||||
github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61/go.mod h1:paQfF1YtHe+GrGg5fOgjsjoCX/UKDr9bc1DoWpZfns8=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw=
|
||||
github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
|
||||
github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/phuslu/log v1.0.113 h1:Koq5A+8ourLX4vhkhW4HCJjo+jEtzMDhqvUUid/5m24=
|
||||
github.com/phuslu/log v1.0.113/go.mod h1:F8osGJADo5qLK/0F88djWwdyoZZ9xDJQL1HYRHFEkS0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pluja/pocketbase v0.0.6 h1:Ah6Qsv3wIcRW+MzrHtVbwD6PkQcz3N5dQRt45NEaWrU=
|
||||
github.com/pluja/pocketbase v0.0.6/go.mod h1:EPXgCTbmMRrirYA0++qkk25xT175zV8PrE0xFpCdUe0=
|
||||
github.com/pluja/pocketbase v0.0.61 h1:p20lrZQbL9EzglbLG2Yw8Ng+vPgSZn+hsKlp/NUPHds=
|
||||
github.com/pluja/pocketbase v0.0.61/go.mod h1:7TGMNQCFq9D7B2k2JdQUVvzUKRBqJKcj/x2+qjcU4Sc=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pocketbase/dbx v1.10.1 h1:cw+vsyfCJD8YObOVeqb93YErnlxwYMkNZ4rwN0G0AaA=
|
||||
github.com/pocketbase/dbx v1.10.1/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
|
||||
github.com/pocketbase/pocketbase v0.20.0 h1:gDatnEZWz4A+PjPuhllLOvirqKLxDkrI3onx27JccV4=
|
||||
github.com/pocketbase/pocketbase v0.20.0/go.mod h1:uy7WOxXoICrwe8HlyR78vTvK0RdG5REkhDx4SvYi4FY=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
|
||||
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=
|
||||
github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
|
||||
github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
|
||||
github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
|
||||
github.com/sashabaranov/go-openai v1.19.4 h1:GbaDiqvgYCabyqzuIbcEeT6/ZX1nVfur+++oTBfOgks=
|
||||
github.com/sashabaranov/go-openai v1.19.4/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||
github.com/sashabaranov/go-openai v1.24.0 h1:4H4Pg8Bl2RH/YSnU8DYumZbuHnnkfioor/dtNlB20D4=
|
||||
github.com/sashabaranov/go-openai v1.24.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||
github.com/sashabaranov/go-openai v1.35.7 h1:icyrRbkYoKPa4rbO1WSInpJu3qDQrPEnsoJVZ6QymdI=
|
||||
github.com/sashabaranov/go-openai v1.35.7/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||
github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
|
||||
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
||||
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
|
||||
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tdewolff/minify/v2 v2.20.16 h1:/C8dtRkxLTIyUlKlBz46gDiktCrE8a6+c1gTrnPFz+U=
|
||||
github.com/tdewolff/minify/v2 v2.20.16/go.mod h1:/FvxV9KaTrFu35J9I2FhRvWSBxcHj8sDSdwBFh5voxM=
|
||||
github.com/tdewolff/minify/v2 v2.20.21 h1:8MCHcxXAVO8B7X+v07mwMWBIEtQo65e1JzBqDgZOQpU=
|
||||
github.com/tdewolff/minify/v2 v2.20.21/go.mod h1:GYaLXFpIIwsX99apQHXfGdISUdlA98wmaoWxjT9C37k=
|
||||
github.com/tdewolff/parse/v2 v2.7.11 h1:v+W45LnzmjndVlfqPCT5gGjAAZKd1GJGOPJveTIkBY8=
|
||||
github.com/tdewolff/parse/v2 v2.7.11/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
|
||||
github.com/tdewolff/parse/v2 v2.7.14 h1:100KJ+QAO3PpMb3uUjzEU/NpmCdbBYz6KPmCIAfWpR8=
|
||||
github.com/tdewolff/parse/v2 v2.7.14/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
|
||||
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/tdewolff/minify/v2 v2.20.19 h1:tX0SR0LUrIqGoLjXnkIzRSIbKJ7PaNnSENLD4CyH6Xo=
|
||||
github.com/tdewolff/minify/v2 v2.20.19/go.mod h1:ulkFoeAVWMLEyjuDz1ZIWOA31g5aWOawCFRp9R/MudM=
|
||||
github.com/tdewolff/parse/v2 v2.7.12 h1:tgavkHc2ZDEQVKy1oWxwIyh5bP4F5fEh/JmBwPP/3LQ=
|
||||
github.com/tdewolff/parse/v2 v2.7.12/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
|
||||
github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo=
|
||||
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||
@ -272,119 +183,58 @@ github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FB
|
||||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
|
||||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
gocloud.dev v0.35.0 h1:x/Gtt5OJdT4j+ir1AXAIXb7bBnFawXAAaJptCUGk3HU=
|
||||
gocloud.dev v0.35.0/go.mod h1:wbyF+BhfdtLWyUtVEWRW13hFLb1vXnV2ovEhYGQe3ck=
|
||||
github.com/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA=
|
||||
github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE=
|
||||
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
|
||||
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
||||
golang.org/x/image v0.16.0 h1:9kloLAKhUufZhA12l5fwnx2NZW39/we1UhBesW433jw=
|
||||
golang.org/x/image v0.16.0/go.mod h1:ugSZItdV4nOxyqp56HmXwH0Ry0nBCpjnZdpDaIHdoPs=
|
||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8=
|
||||
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
|
||||
golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68=
|
||||
golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
|
||||
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
|
||||
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||
google.golang.org/api v0.153.0 h1:N1AwGhielyKFaUqH07/ZSIQR3uNPcV7NVw0vj+j4iR4=
|
||||
google.golang.org/api v0.153.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 h1:DC7wcm+i+P1rN3Ff07vL+OndGg5OhNddHyTA+ocPqYE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM=
|
||||
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
|
||||
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
|
17
src/internal/cache/cache.go
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
package cache
|
||||
|
||||
import "github.com/dgraph-io/ristretto"
|
||||
|
||||
var Cache *ristretto.Cache
|
||||
|
||||
func Init() {
|
||||
var err error
|
||||
Cache, err = ristretto.NewCache(&ristretto.Config{
|
||||
NumCounters: 1e7, // number of keys to track frequency of (10M).
|
||||
MaxCost: 1 << 30, // maximum cost of cache (1GB).
|
||||
BufferItems: 64, // number of keys per Get buffer.
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
37
src/internal/database/client.go
Normal file
@ -0,0 +1,37 @@
|
||||
// client.go
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"entgo.io/ent/dialect"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/phuslu/log"
|
||||
|
||||
"kycnot.me/internal/ent"
|
||||
"kycnot.me/utils"
|
||||
)
|
||||
|
||||
var client *ent.Client
|
||||
|
||||
// Init initializes the database client.
|
||||
func Init() {
|
||||
var err error
|
||||
// client, err = ent.Open(dialect.SQLite, "file:ent?mode=memory&cache=shared&_fk=1")
|
||||
// client, err = ent.Open(dialect.SQLite, "file:./db.sql?cache=shared&_fk=1")
|
||||
log.Printf("%s", os.Getenv("DATABASE_URI"))
|
||||
client, err = ent.Open(dialect.MySQL, utils.Getenv("DATABASE_URI", "kycnot:kycnot@tcp(database:3306)/kycnot?parseTime=True"))
|
||||
if err != nil {
|
||||
log.Fatal().Msgf("failed opening connection to MYSQL: %v", err)
|
||||
}
|
||||
|
||||
// Run the auto migration tool.
|
||||
if err := client.Schema.Create(context.Background()); err != nil {
|
||||
log.Fatal().Msgf("failed creating schema resources: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Client() *ent.Client {
|
||||
return client
|
||||
}
|