It's time to rewrite burgernotes!! Again!!!!!!!
This commit is contained in:
parent
795fa524d0
commit
3db8328cac
|
@ -1,4 +1,4 @@
|
|||
database.db
|
||||
config.ini
|
||||
config.ini.example
|
||||
.idea
|
||||
# IntelliJ IDEA
|
||||
.idea
|
||||
# Protocol Buffers
|
||||
git.ailur.dev
|
384
APIDOCS.md
384
APIDOCS.md
|
@ -1,135 +1,313 @@
|
|||
# 🍔 Burgernotes API docs
|
||||
Use the Burgernotes API to automate tasks, build your own client, and more!
|
||||
# API documentation
|
||||
|
||||
Headers should be: "Content-type: application/json; charset=UTF-8" for all POSTs
|
||||
The Burgernotes API is a RESTful API that allows you to interact with the Burgernotes service. The API is designed to be simple and easy to use.
|
||||
It uses Protocol Buffers for serialization and deserialization, and POST requests for all operations.
|
||||
|
||||
## 🔑 Authentication
|
||||
## Protobuf types
|
||||
These are some basic Protobuf types that are used in the API.
|
||||
All protocol buffers are using proto3 syntax.
|
||||
```protobuf
|
||||
syntax = "proto3";
|
||||
|
||||
POST - /api/signup - provide "username" and "password".
|
||||
// Token is a string that represents an OAuth2 JWT token.
|
||||
message Token {
|
||||
string token = 1;
|
||||
}
|
||||
|
||||
POST - /api/login - provide "username" and "password"
|
||||
// NoteID is a UUID that represents a note.
|
||||
message NoteID {
|
||||
bytes noteId = 1;
|
||||
}
|
||||
|
||||
To prevent the server from knowing the encryption key, the password you provide in the request must be hashed with Argon2ID as per the following parameters:
|
||||
|
||||
- salt: UTF-8 Representation of "I munch Burgers!!" (should be 16 bytes),
|
||||
- parallelism: 1
|
||||
- iterations: 32
|
||||
- memorySize: 19264 bytes
|
||||
- hashLength: 32
|
||||
- outputType: hexadecimal
|
||||
// NoteID and Token together represent a request involving a note.
|
||||
message NoteRequest {
|
||||
NoteID noteId = 1;
|
||||
Token token = 2;
|
||||
}
|
||||
|
||||
Password should be at least 8 characters, username must be under 20 characters and alphanumeric.
|
||||
// AESData represents AES-encrypted data.
|
||||
message AESData {
|
||||
bytes data = 2;
|
||||
bytes iv = 3;
|
||||
}
|
||||
|
||||
If username is taken, error code 422 will return.
|
||||
// NoteMetadata represents the metadata of a note.
|
||||
message NoteMetadata {
|
||||
NoteID noteId = 1;
|
||||
AESData title = 2;
|
||||
}
|
||||
|
||||
Assuming everything went correctly, the server will return a secret key.
|
||||
// Note represents a note.
|
||||
message Note {
|
||||
NoteMetadata metadata = 1;
|
||||
AESData note = 2;
|
||||
}
|
||||
|
||||
You'll need to store two things in local storage:
|
||||
- The secret key you just got, used to fetch notes, save stuff etc.
|
||||
- Another password, which is hashed the same way, but with a salt of "I love Burgernotes!" (again, UTF-8 representation, 16 bytes).
|
||||
// Invitation represents an invitation to a note.
|
||||
message Invitation {
|
||||
string username = 1;
|
||||
AESData key = 2;
|
||||
NoteID noteId = 3;
|
||||
}
|
||||
|
||||
If you are using the OAuth2 flow (totally optional, I know it's really complex) then you should also store the login password to use later, or put the OAuth2 logic straight after this.
|
||||
// User represents a user editing notes.
|
||||
message UserLines {
|
||||
string username = 1;
|
||||
bytes uuid = 2;
|
||||
repeated uint64 lines = 3;
|
||||
}
|
||||
|
||||
## 🌐 OAuth2 + Burgerauth
|
||||
// Error represents an error.
|
||||
message Error {
|
||||
string error = 1;
|
||||
}
|
||||
|
||||
For security purposes, traditional OAuth2 is not supported. Instead, we use Burgerauth, a custom OAuth2 implementation that provides a unique-yet-consistent "authentication code" for each user. It is created in a special way as to not involve the server, meaning the security of Burgernotes is not compromised by using OAuth2, which is normally a very server-side process.
|
||||
|
||||
### How it works
|
||||
First, perform regular client-side OAuth2 authentication using Burgerauth, as detailed in its [own documentation](https://concord.hectabit.org/HectaBit/burgerauth/src/branch/main/APIDOCS.md). Once regular OAuth2 is complete, you will be given an authentication code, which is important for the next step.
|
||||
|
||||
You now have one of two options:
|
||||
1. If your app is based on the web, you can host a static page provided [here](https://concord.hectabit.org/HectaBit/burgerauth/src/branch/main/keyExchangeRdir.html) on any static service. Redirect to this page with the OAuth2 token stored in localStorage as BURGERAUTH-RDIR-TOKEN. The page will then communicate with a corresponding page on Burgerauth, and transmit the key securely via RSA. You may see the page redirect a couple of times as it communicates the infomation across. All you need to know is that once it is finished, it will redirect back to the page that redirected to it with the key in localStorage as DONOTSHARE-EXCHANGED-KEY.
|
||||
2. If your app is not web-based, you can open up a webview to [here](https://auth.hectabit.org/keyexchangeclient). Once it is finished, it will send a postMessage with the body "finished" to the target "*" and output "finished" to the JavaScript console. The key will be in localStorage as DONOTSHARE-EXCHANGED-KEY.
|
||||
3. Alternatively, you can host a local webserver and host the aforementioned page on it. It will work the same way as the first option, and once it is finished, it will detect that it was not redirected to and instead will set it as a cookie expiring in 5 minutes and then refresh the page. You should detect for the cookie and use its value, and then kill the webserver. This method is not recommended because of its complexity and overhead.
|
||||
|
||||
Once this is finished, you should check if there is an existing OAuth2 entry on the server like this:
|
||||
|
||||
POST - /api/oauth/get - provide "username" and "oauthProvider"
|
||||
oauthProvider is the name of the OAuth2 provider, such as "burgerauth" or "google" (google is used as an example, they do not use the burgerauth extensions and are therefore incompatible).
|
||||
It does not have to be the actual name, but it has to be unique to the provider (per user). The sub given by OpenID Connect is a good choice.
|
||||
|
||||
### 404 is returned
|
||||
No entry has been found, and you have to log in the user as normal.
|
||||
Once this is done, you should create an entry like this:
|
||||
|
||||
POST - /api/oauth/new - provide "secretKey", "oauthProvider" and "encryptedPassword"
|
||||
|
||||
To create encryptedPassword, follow these steps:
|
||||
|
||||
1. Generate a random 16-byte IV.
|
||||
2. Create a JSON structure like this:
|
||||
```json
|
||||
{
|
||||
"loginPass": "(the SHA-3 password hash created in the login process)",
|
||||
"cryptoPass": "(the SHA-512 password hash stored in localStorage)"
|
||||
// ServerError represents a 500 error, with a hex error code.
|
||||
message ServerError {
|
||||
bytes errorCode = 1;
|
||||
}
|
||||
```
|
||||
3. Convert the JSON to a string and then encrypt it using AES-256 GCM using the exchangeKey as the key and the IV created earlier as the IV.
|
||||
4. Create a JSON structure like this:
|
||||
```json
|
||||
{
|
||||
"iv": "(the IV)",
|
||||
"content": "(the encrypted JSON)"
|
||||
## Errors
|
||||
In any response, if an error occurs, it will return an `Error` or `ServerError` message.
|
||||
### 400 Range
|
||||
```protobuf
|
||||
message Error {
|
||||
string error = 1;
|
||||
}
|
||||
```
|
||||
5. Finally, convert the JSON into a string, base64 encode it, and send it off as encryptedPassword.
|
||||
The error is formatted to be human-readable, you may display it to the user.
|
||||
### HTTP 500
|
||||
```protobuf
|
||||
message ServerError {
|
||||
bytes errorCode = 1;
|
||||
}
|
||||
```
|
||||
ServerError is a hex byte which represents the error code. You should give a vague error message to the user.
|
||||
|
||||
Do not store the exchangeKey after this point, as it is no longer needed.
|
||||
## Authentication
|
||||
### /api/signup - POST
|
||||
#### Request
|
||||
```protobuf
|
||||
message ApiSignupRequest {
|
||||
bytes publicKey = 1;
|
||||
Token token = 2;
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
200 OK
|
||||
No response body
|
||||
|
||||
### 200 is returned
|
||||
An entry exists, and encryptedPassword has been returned using JSON.
|
||||
encryptedPassword is the password encrypted using AES-256 GCM, and the IV is included in the JSON, in this format defined above.
|
||||
### /api/delete - POST - Show a warning before this action!
|
||||
#### Request
|
||||
```protobuf
|
||||
message Token {
|
||||
string token = 1;
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
HTTP 200 OK
|
||||
No response body
|
||||
|
||||
Use the passwords defined in the JSON structure before the last one to log in normally.
|
||||
## Interacting with notes
|
||||
### /api/notes/add - POST
|
||||
#### Request
|
||||
```protobuf
|
||||
message Token {
|
||||
string token = 1;
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
HTTP 200 OK
|
||||
```protobuf
|
||||
message NoteID {
|
||||
bytes noteId = 1;
|
||||
}
|
||||
```
|
||||
|
||||
#### Finally, you are done!
|
||||
### /api/notes/remove - POST
|
||||
#### Request
|
||||
```protobuf
|
||||
message NoteRequest {
|
||||
NoteID noteId = 1;
|
||||
Token token
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
HTTP 200 OK
|
||||
No response body
|
||||
|
||||
## 🔐 Encryption
|
||||
### /api/notes/list - POST
|
||||
#### Request
|
||||
```protobuf
|
||||
message Token {
|
||||
string token = 1;
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
HTTP 200 OK
|
||||
```protobuf
|
||||
message ApiNotesListResponse {
|
||||
repeated NoteMetadata notes = 1;
|
||||
}
|
||||
```
|
||||
|
||||
Note content and title is encrypted using AES 256-bit.
|
||||
### /api/notes/get - POST
|
||||
#### Request
|
||||
```protobuf
|
||||
message NoteRequest {
|
||||
NoteID noteId = 1;
|
||||
Token token
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
HTTP 200 OK
|
||||
```protobuf
|
||||
message Note {
|
||||
NoteMetadata metadata = 1;
|
||||
AESData note = 2;
|
||||
}
|
||||
```
|
||||
|
||||
Encryption password is the SHA512 hashed password we talked about earlier.
|
||||
### /api/notes/edit - POST
|
||||
#### Request
|
||||
```protobuf
|
||||
message ApiNotesEditRequest {
|
||||
Note note = 1;
|
||||
Token token = 2;
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
HTTP 200 OK
|
||||
No response body
|
||||
|
||||
## 🕹️ Basic stuff
|
||||
### /api/notes/purge - POST - Show a warning before this action!
|
||||
#### Request
|
||||
```protobuf
|
||||
message Token {
|
||||
string token = 1;
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
HTTP 200 OK
|
||||
No response body
|
||||
|
||||
POST - /api/userinfo - get user info such as username, provide "secretKey"
|
||||
## Shared notes - This is not yet implemented
|
||||
### /api/invite/prepare - POST
|
||||
#### Request
|
||||
```protobuf
|
||||
message ApiInvitePrepareRequest {
|
||||
string username = 1;
|
||||
Token token = 2;
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
HTTP 200 OK
|
||||
```protobuf
|
||||
message ApiInvitePrepareResponse {
|
||||
bytes ecdhExchange = 1;
|
||||
}
|
||||
```
|
||||
|
||||
POST - /api/listnotes - list notes, provide "secretKey"
|
||||
note titles will have to be decrypted.
|
||||
### /api/invite/check - POST
|
||||
#### Request
|
||||
```protobuf
|
||||
message Token {
|
||||
string token = 1;
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
HTTP 200 OK
|
||||
```protobuf
|
||||
message ApiInviteCheckResponse {
|
||||
repeated Invitation invitations = 1;
|
||||
}
|
||||
```
|
||||
|
||||
POST - /api/newnote - create a note, provide "secretKey" and "noteName"
|
||||
"noteName" should be encrypted using AES-256 GCM with the DONOTSHARE-password as the key and a random 16-byte IV.
|
||||
### /api/invite/link - POST
|
||||
#### Request
|
||||
```protobuf
|
||||
message ApiInviteLinkRequest {
|
||||
NoteRequest noteRequest = 1;
|
||||
int64 timestamp = 2;
|
||||
bool singleUse = 3;
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
HTTP 200 OK
|
||||
```protobuf
|
||||
message ApiInviteLinkResponse {
|
||||
bytes inviteCode = 1;
|
||||
}
|
||||
```
|
||||
|
||||
POST - /api/readnote - read notes, provide "secretKey" and "noteId"
|
||||
note content will have to be decrypted.
|
||||
### /api/invite/accept - POST
|
||||
#### Request
|
||||
```protobuf
|
||||
message ApiInviteAcceptRequest {
|
||||
bytes inviteCode = 1;
|
||||
Token token = 2;
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
HTTP 200 OK
|
||||
```protobuf
|
||||
message NoteID {
|
||||
bytes noteId = 1;
|
||||
}
|
||||
```
|
||||
|
||||
POST - /api/editnote - edit notes, provide "secretKey", "noteId", "title", and "content"
|
||||
"content" should be encrypted using AES-256 GCM with the DONOTSHARE-password as the key and a random 16-byte IV.
|
||||
"title" is the first line of the note content, and should be encrypted.
|
||||
### /api/invite/leave - POST
|
||||
#### Request
|
||||
```protobuf
|
||||
message NoteRequest {
|
||||
NoteID noteId = 1;
|
||||
Token token
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
HTTP 200 OK
|
||||
No response body
|
||||
|
||||
POST - /api/removenote - remove notes, provide "secretKey" and "noteId"
|
||||
### /api/shared - WebSocket
|
||||
Every heartbeat interval (500ms):
|
||||
#### Request
|
||||
```protobuf
|
||||
message ApiSharedRequest {
|
||||
repeated uint64 lines = 1;
|
||||
Token token = 2;
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
```protobuf
|
||||
message ApiSharedResponse {
|
||||
repeated UserLines users = 1;
|
||||
}
|
||||
```
|
||||
|
||||
POST - /api/purgenotes - remove all notes, provide "secretKey"
|
||||
### Please display a warning before this action
|
||||
### /api/shared/edit - POST
|
||||
#### Request
|
||||
```protobuf
|
||||
message ApiSharedEditRequest {
|
||||
repeated AESData lines = 1;
|
||||
Token token = 2;
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
HTTP 200 OK
|
||||
No response body
|
||||
|
||||
## ⚙️ Account management
|
||||
|
||||
POST - /api/changepassword - change account password, provide "secretKey", "newPassword"
|
||||
encrypt the same way as /api/login
|
||||
|
||||
POST - /api/deleteaccount - delete account, provide "secretKey"
|
||||
### Please display a warning before this action
|
||||
|
||||
POST - /api/exportnotes - export notes, provide "secretKey"
|
||||
note content and title will have to be decrypted
|
||||
|
||||
POST - /api/importnotes - import notes, provide "secretKey" and "notes"
|
||||
note content and title should be encrypted using AES-256 GCM with the DONOTSHARE-password as the key and a random 16-byte IV and follow the /api/exportnotes format, in a marshalled json string
|
||||
|
||||
POST - /api/sessions/list - show all sessions, provide "secretKey"
|
||||
|
||||
POST - /api/sessions/remove - remove session, provide "secretKey" and "sessionId"
|
||||
|
||||
## 💼 Admin controls
|
||||
|
||||
POST - /api/listusers - lists all users in JSON, provide "masterKey" (set in config.ini)
|
||||
### /api/shared/get - POST
|
||||
#### Request
|
||||
```protobuf
|
||||
message NoteRequest {
|
||||
NoteID noteId = 1;
|
||||
Token token
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
```protobuf
|
||||
message ApiSharedGetResponse {
|
||||
repeated AESData lines = 1;
|
||||
NoteMetadata metadata = 2;
|
||||
}
|
||||
```
|
23
ERRORS.md
23
ERRORS.md
|
@ -1,23 +0,0 @@
|
|||
# Errors in Burger-based software and how to handle them
|
||||
|
||||
## The console
|
||||
|
||||
All Burger-based software uses a simple logging system that outputs to TTY. Log files are not provided by default and users are expected to use pipes to redirect the logs as they wish.
|
||||
|
||||
A log entry looks something like this:
|
||||
|
||||
| DATE | HUMAN-READABLE TIME | LOGLEVEL | DESCRIPTION |
|
||||
|---|---|---|---|---|
|
||||
| 1969/12/31 | 11:59:59 | [INFO] | Added a new user |
|
||||
|
||||
## Log levels
|
||||
|
||||
There are 5 different log levels, with differing amounts of urgency
|
||||
|
||||
| INFO | WARN | ERROR | CRITICAL | FATAL | PROMPT |
|
||||
|---------------------------------------------------------|---------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|-------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|
|
||||
| Usually harmless information, like a user being created | A warning about bad practices being used, such as having an unset config option | An error that disrupts user experience and may lead to undesired client-side behaviour | An error that affects all users on the platform | An error critical enough to warrant crashing the server process, usually something like the server being unable to bind to an IP or not being able to create the database | Anything that asks the user for input, like a confirmation dialog (typically has no timestamp) |
|
||||
|
||||
## Error reporting
|
||||
|
||||
Clients will be given 500 status code and an error code if any errors were to affect them. They are told to come to this page for more information. If you are one such client, please go to the issues tab and paste the error code along with some context, so we can fix the bug.
|
27
README.md
27
README.md
|
@ -2,18 +2,33 @@
|
|||
Burgernotes is a simple note-taking app with end-to-end encryption.
|
||||
|
||||
### Setup
|
||||
To set up Burgernotes, simply run these commands:
|
||||
To set up Burgernotes, set it up like any other Fulgens Server module.
|
||||
```
|
||||
cp config.ini.example config.ini
|
||||
./burgernotes init_db
|
||||
cd /path/to/fulgens/directory
|
||||
git clone https://git.ailur.dev/ailur/burgernotes.git --depth=1 services-src/burgernotes
|
||||
```
|
||||
If you want to rebuild all of fulgens (recommended), run `./build.sh` in the fulgens directory.
|
||||
If you only want to build the Burgernotes module, run `services-src/burgernotes/build.sh`.
|
||||
|
||||
### Configuration
|
||||
Edit the main `config.json` file to include the Burgernotes module in the `services` object.
|
||||
```json
|
||||
{
|
||||
"burgernotes": {
|
||||
"subdomain": "notes.example.org",
|
||||
"hostName": "https://notes.example.org"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Edit config.ini to your liking, then to start the server run:
|
||||
### Running
|
||||
Run the Fulgens server as you normally would.
|
||||
```
|
||||
./burgernotes
|
||||
./fulgens
|
||||
```
|
||||
|
||||
### Links
|
||||
[Go to the Burgernotes website](https://notes.hectabit.org)
|
||||
[Go to the Burgernotes website](https://notes.ailur.dev)
|
||||
|
||||
[API documentation](APIDOCS.md)
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# Burgernotes Roadmap
|
||||
|
||||
- Switch to WebSockets for updating notes + live updating of note list and more, this involves redoing some APIs
|
||||
- Compress notes to reduce bandwidth and storage
|
||||
- Use Burgerauth for authentication
|
||||
- Dedicated domain (not just a subdomain, if anyone can donate a domain let Arzumify know!)
|
||||
- Create the frontend
|
||||
- Implementing shared notes
|
||||
- Dedicated domain (not just a subdomain, if anyone can donate a domain let Arzumify know!)
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
path=$(realpath "$(dirname "$0")") || exit 1
|
||||
rm -rf "$path/../../services/burgernotes.fgs" || exit 1
|
||||
cd "$path" || exit 1
|
||||
protoc -I="$path" --go_out="$path" "$path/protobufs/main.proto" || exit 1
|
||||
go build -o "$path/../../services/burgernotes.fgs" --buildmode=plugin -ldflags "-s -w" || exit 1
|
|
@ -1,5 +0,0 @@
|
|||
[config]
|
||||
HOST = 0.0.0.0
|
||||
PORT = 8080
|
||||
SECRET_KEY = supersecretkey
|
||||
MAX_STORAGE = 25000000
|
|
@ -0,0 +1 @@
|
|||
package main
|
59
go.mod
59
go.mod
|
@ -1,58 +1,15 @@
|
|||
module hectabit.org/burgernotes
|
||||
module git.ailur.dev/ailur/burgernotes
|
||||
|
||||
go 1.22
|
||||
go 1.23.1
|
||||
|
||||
require (
|
||||
github.com/catalinc/hashcash v1.0.0
|
||||
github.com/gin-contrib/sessions v1.0.1
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/mattn/go-sqlite3 v1.14.22
|
||||
github.com/spf13/viper v1.19.0
|
||||
golang.org/x/crypto v0.23.0
|
||||
git.ailur.dev/ailur/fg-library/v2 v2.0.1
|
||||
git.ailur.dev/ailur/fg-nucleus-library v1.0.2
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
github.com/google/uuid v1.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.11.6 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/gorilla/context v1.1.2 // indirect
|
||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||
github.com/gorilla/sessions v1.2.2 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
github.com/go-chi/chi/v5 v5.1.0
|
||||
google.golang.org/protobuf v1.35.1
|
||||
)
|
||||
|
|
160
go.sum
160
go.sum
|
@ -1,144 +1,16 @@
|
|||
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/catalinc/hashcash v1.0.0 h1:DiI2kBNCczy7y3xJnLddIl7KGx0yP4B7irFZZ+yzzwc=
|
||||
github.com/catalinc/hashcash v1.0.0/go.mod h1:ldWL6buwYCK4VqIkLbZuFbGUoJceSafm8duCEQYw9Jw=
|
||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
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/gin-contrib/sessions v1.0.1 h1:3hsJyNs7v7N8OtelFmYXFrulAf6zSR7nW/putcPEHxI=
|
||||
github.com/gin-contrib/sessions v1.0.1/go.mod h1:ouxSFM24/OgIud5MJYQJLpy6AwxQ5EYO9yLhbtObGkM=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
|
||||
github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM=
|
||||
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
||||
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||
github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
|
||||
github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
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/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/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-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
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/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.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/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-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
git.ailur.dev/ailur/fg-library/v2 v2.0.1 h1:ltPYXf/Om0hnMD8gr1K5bkYrfHqKPSbb0hxa0wtTnZ0=
|
||||
git.ailur.dev/ailur/fg-library/v2 v2.0.1/go.mod h1:1jYbWhabGcIwp7CkhHqvRwC8eP+nHv5BrXPe9NX2HE8=
|
||||
git.ailur.dev/ailur/fg-nucleus-library v1.0.2 h1:EWfeab+wJKaxx/Qg5TKpvZHicA0V/NilUv2g6W97rtg=
|
||||
git.ailur.dev/ailur/fg-nucleus-library v1.0.2/go.mod h1:T2mdUiXlZqb917CkNB2vwujkD/QhJDpCHLRvKuskBpY=
|
||||
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
||||
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
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=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
syntax = "proto3";
|
||||
package main;
|
||||
option go_package = "git.ailur.dev/ailur/burgernotes/protobuf";
|
||||
|
||||
// Token is a string that represents an OAuth2 JWT token.
|
||||
message Token {
|
||||
string token = 1;
|
||||
}
|
||||
|
||||
// NoteID is a UUID that represents a note.
|
||||
message NoteID {
|
||||
bytes noteId = 1;
|
||||
}
|
||||
|
||||
// NoteID and Token together represent a request involving a note.
|
||||
message NoteRequest {
|
||||
NoteID noteId = 1;
|
||||
Token token = 2;
|
||||
}
|
||||
|
||||
// AESData represents AES-encrypted data.
|
||||
message AESData {
|
||||
bytes data = 2;
|
||||
bytes iv = 3;
|
||||
}
|
||||
|
||||
// NoteMetadata represents the metadata of a note.
|
||||
message NoteMetadata {
|
||||
NoteID noteId = 1;
|
||||
AESData title = 2;
|
||||
}
|
||||
|
||||
// Note represents a note.
|
||||
message Note {
|
||||
NoteMetadata metadata = 1;
|
||||
AESData note = 2;
|
||||
}
|
||||
|
||||
// /api/notes/list returns an array of notes.
|
||||
message ApiNotesListResponse {
|
||||
repeated NoteMetadata notes = 1;
|
||||
}
|
||||
|
||||
// /api/notes/edit accepts a note and a token.
|
||||
message ApiNotesEditRequest {
|
||||
Note note = 1;
|
||||
Token token = 2;
|
||||
}
|
||||
|
||||
// /api/signup accepts a public key and a token.
|
||||
message ApiSignupRequest {
|
||||
bytes publicKey = 1;
|
||||
Token token = 2;
|
||||
}
|
||||
|
||||
// /api/invite/prepare accepts an username and a token.
|
||||
message ApiInvitePrepareRequest {
|
||||
string username = 1;
|
||||
Token token = 2;
|
||||
}
|
||||
|
||||
// /api/invite/prepare returns a ECDH key.
|
||||
message ApiInvitePrepareResponse {
|
||||
bytes ecdhExchange = 1;
|
||||
}
|
||||
|
||||
// /api/invite/send accepts a ECDH exchange, a AES-encrypted key and a NoteRequest.
|
||||
message ApiInviteSendRequest {
|
||||
bytes ecdhExchange = 1;
|
||||
AESData key = 2;
|
||||
NoteRequest noteRequest = 3;
|
||||
}
|
||||
|
||||
// Invitation represents an invitation to a note.
|
||||
message Invitation {
|
||||
string username = 1;
|
||||
AESData key = 2;
|
||||
NoteID noteId = 3;
|
||||
}
|
||||
|
||||
// /api/invite/check returns an array of invitations.
|
||||
message ApiInviteCheckResponse {
|
||||
repeated Invitation invitations = 1;
|
||||
}
|
||||
|
||||
// /api/invite/link accepts a NoteRequest, UNIX timestamp and a singleUse boolean.
|
||||
message ApiInviteLinkRequest {
|
||||
NoteRequest noteRequest = 1;
|
||||
int64 timestamp = 2;
|
||||
bool singleUse = 3;
|
||||
}
|
||||
|
||||
// /api/invite/link returns an invite code.
|
||||
message ApiInviteLinkResponse {
|
||||
bytes inviteCode = 1;
|
||||
}
|
||||
|
||||
// /api/invite/accept accepts an invite code and a token.
|
||||
message ApiInviteAcceptRequest {
|
||||
bytes inviteCode = 1;
|
||||
Token token = 2;
|
||||
}
|
||||
|
||||
// /api/shared is a WebSocket which accepts an array of line numbers and a token.
|
||||
message ApiSharedRequest {
|
||||
repeated uint64 lines = 1;
|
||||
Token token = 2;
|
||||
}
|
||||
|
||||
// User represents a user editing notes.
|
||||
message UserLines {
|
||||
string username = 1;
|
||||
bytes uuid = 2;
|
||||
repeated uint64 lines = 3;
|
||||
}
|
||||
|
||||
// /api/shared is a WebSocket which returns the array of line numbers for each user working on a note.
|
||||
message ApiSharedResponse {
|
||||
repeated UserLines users = 1;
|
||||
}
|
||||
|
||||
// /api/shared/edit accepts multiple lines, represented as an individual AESData, and a token.
|
||||
message ApiSharedEditRequest {
|
||||
repeated AESData lines = 1;
|
||||
Token token = 2;
|
||||
}
|
||||
|
||||
// /api/shared/get returns the lines of a note.
|
||||
message ApiSharedGetResponse {
|
||||
repeated AESData lines = 1;
|
||||
NoteMetadata metadata = 2;
|
||||
}
|
||||
|
||||
// Error represents an error.
|
||||
message Error {
|
||||
string error = 1;
|
||||
}
|
||||
|
||||
// ServerError represents a 500 error, with a hex error code.
|
||||
message ServerError {
|
||||
bytes errorCode = 1;
|
||||
}
|
27
schema.sql
27
schema.sql
|
@ -1,27 +0,0 @@
|
|||
DROP TABLE IF EXISTS users;
|
||||
DROP TABLE IF EXISTS notes;
|
||||
DROP TABLE IF EXISTS oauth;
|
||||
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created TEXT NOT NULL,
|
||||
username TEXT NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
migrated INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE notes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
creator INTEGER NOT NULL,
|
||||
created TEXT NOT NULL,
|
||||
edited TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
title TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE oauth (
|
||||
id INTEGER NOT NULL,
|
||||
oauthProvider TEXT NOT NULL,
|
||||
encryptedPasswd TEXT NOT NULL,
|
||||
UNIQUE (id, oauthProvider)
|
||||
)
|
Loading…
Reference in New Issue