-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f7e8ff0
commit 0418ccc
Showing
69 changed files
with
6,994 additions
and
6,976 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
; editorconfig.org | ||
root = true | ||
|
||
[*] | ||
indent_style = space | ||
indent_size = 2 | ||
end_of_line = lf | ||
charset = utf-8 | ||
trim_trailing_whitespace = true | ||
insert_final_newline = true | ||
|
||
[{Makefile,go.mod,go.sum,*.go,.gitmodules}] | ||
indent_style = tab | ||
indent_size = 4 | ||
|
||
[*.md] | ||
indent_size = 4 | ||
trim_trailing_whitespace = false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,16 @@ | ||
version: 2 | ||
updates: | ||
- package-ecosystem: "gomod" | ||
directory: "/backend" | ||
schedule: | ||
interval: "weekly" | ||
day: "saturday" | ||
- package-ecosystem: "npm" | ||
directory: "/frontend" | ||
schedule: | ||
interval: "weekly" | ||
day: "saturday" | ||
- package-ecosystem: "github-actions" | ||
directory: "/" | ||
schedule: | ||
interval: "monthly" | ||
version: 2 | ||
updates: | ||
- package-ecosystem: "gomod" | ||
directory: "/backend" | ||
schedule: | ||
interval: "weekly" | ||
day: "saturday" | ||
- package-ecosystem: "npm" | ||
directory: "/frontend" | ||
schedule: | ||
interval: "weekly" | ||
day: "saturday" | ||
- package-ecosystem: "github-actions" | ||
directory: "/" | ||
schedule: | ||
interval: "monthly" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,45 @@ | ||
name: CI | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
pull_request: | ||
branches: | ||
- main | ||
workflow_dispatch: | ||
|
||
jobs: | ||
build-frontend: | ||
runs-on: ubuntu-latest | ||
defaults: | ||
run: | ||
working-directory: ./frontend | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: actions/setup-node@v3 | ||
with: | ||
node-version: 18 | ||
- uses: pnpm/action-setup@v2 | ||
with: | ||
version: 8 | ||
- run: pnpm install --frozen-lockfile | ||
- run: pnpm typecheck | ||
- run: pnpm lint | ||
- run: pnpm generate | ||
|
||
build-backend: | ||
runs-on: ubuntu-latest | ||
defaults: | ||
run: | ||
working-directory: ./backend | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: actions/setup-go@v4 | ||
with: | ||
version: "1.20" | ||
- run: go build -v ./... | ||
- run: go test -v ./... -cover -covermode=atomic -coverpkg=./... -coverprofile=coverage.txt | ||
- uses: codecov/codecov-action@v3 | ||
with: | ||
token: ${{secrets.CODECOV_TOKEN}} | ||
name: CI | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
pull_request: | ||
branches: | ||
- main | ||
workflow_dispatch: | ||
|
||
jobs: | ||
build-frontend: | ||
runs-on: ubuntu-latest | ||
defaults: | ||
run: | ||
working-directory: ./frontend | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: actions/setup-node@v3 | ||
with: | ||
node-version: 18 | ||
- uses: pnpm/action-setup@v2 | ||
with: | ||
version: 8 | ||
- run: pnpm install --frozen-lockfile | ||
- run: pnpm typecheck | ||
- run: pnpm lint | ||
- run: pnpm generate | ||
|
||
build-backend: | ||
runs-on: ubuntu-latest | ||
defaults: | ||
run: | ||
working-directory: ./backend | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: actions/setup-go@v4 | ||
with: | ||
version: "1.20" | ||
- run: go build -v ./... | ||
- run: go test -v ./... -cover -covermode=atomic -coverpkg=./... -coverprofile=coverage.txt | ||
- uses: codecov/codecov-action@v3 | ||
with: | ||
token: ${{secrets.CODECOV_TOKEN}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
.env | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
/data | ||
/test/data | ||
/data | ||
/test/data |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,22 @@ | ||
package main | ||
|
||
import ( | ||
"embed" | ||
"io/fs" | ||
"log" | ||
"net/http" | ||
) | ||
|
||
//go:generate rm -r ./static/* | ||
//go:generate cp -r ../frontend/.output/public/* ./static/ | ||
//go:embed all:static | ||
var frontendFs embed.FS | ||
|
||
func getStaticFrontend() http.FileSystem { | ||
fsys, err := fs.Sub(frontendFs, "static") | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
return http.FS(fsys) | ||
} | ||
package main | ||
|
||
import ( | ||
"embed" | ||
"io/fs" | ||
"log" | ||
"net/http" | ||
) | ||
|
||
//go:generate rm -r ./static/* | ||
//go:generate cp -r ../frontend/.output/public/* ./static/ | ||
//go:embed all:static | ||
var frontendFs embed.FS | ||
|
||
func getStaticFrontend() http.FileSystem { | ||
fsys, err := fs.Sub(frontendFs, "static") | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
return http.FS(fsys) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,93 +1,93 @@ | ||
package argon2 | ||
|
||
import ( | ||
"crypto/rand" | ||
"crypto/subtle" | ||
"encoding/base64" | ||
"errors" | ||
"fmt" | ||
"strings" | ||
|
||
"golang.org/x/crypto/argon2" | ||
) | ||
|
||
// Inspired by https://www.alexedwards.net/blog/how-to-hash-and-verify-passwords-with-argon2-in-go | ||
|
||
// HashPasswordDefault returns hash using argon2id and default parameters | ||
func HashPasswordDefault(password string) (string, error) { | ||
return HashPassword(password, 32, 16, 1, 65536, 2) | ||
} | ||
|
||
// HashPassword returns hash using argon2id and the provided parameters | ||
func HashPassword(password string, keyLength, saltLength, iterations, memory uint32, parallelism uint8) (string, error) { | ||
salt := make([]byte, saltLength) | ||
_, err := rand.Read(salt) | ||
if err != nil { | ||
return "", fmt.Errorf("could not create salt: %w", err) | ||
} | ||
|
||
key := argon2.IDKey([]byte(password), salt, iterations, memory, parallelism, keyLength) | ||
|
||
hash := fmt.Sprintf("$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s", | ||
argon2.Version, | ||
memory, | ||
iterations, | ||
parallelism, | ||
base64.RawStdEncoding.EncodeToString(salt), | ||
base64.RawStdEncoding.EncodeToString(key)) | ||
|
||
return hash, nil | ||
} | ||
|
||
// VerifyPassword checks if password matches the hash, supports argon2id and argon2i | ||
func VerifyPassword(password, hash string) (match bool, err error) { | ||
hashParts := strings.Split(hash, "$") | ||
if len(hashParts) != 6 { | ||
return false, errors.New("invalid hash format") | ||
} | ||
|
||
variant := hashParts[1] | ||
|
||
var version int | ||
_, err = fmt.Sscanf(hashParts[2], "v=%d", &version) | ||
if err != nil { | ||
return false, fmt.Errorf("could not parse version: %w", err) | ||
} | ||
if version != argon2.Version { | ||
return false, fmt.Errorf("incompatible version: %d", version) | ||
} | ||
|
||
var memory uint32 | ||
var iterations uint32 | ||
var parallelism uint8 | ||
|
||
_, err = fmt.Sscanf(hashParts[3], "m=%d,t=%d,p=%d", &memory, &iterations, ¶llelism) | ||
if err != nil { | ||
return false, fmt.Errorf("could not parse parameters: %w", err) | ||
} | ||
|
||
salt, err := base64.RawStdEncoding.Strict().DecodeString(hashParts[4]) | ||
if err != nil { | ||
return false, fmt.Errorf("could not decode salt: %w", err) | ||
} | ||
|
||
key, err := base64.RawStdEncoding.Strict().DecodeString(hashParts[5]) | ||
if err != nil { | ||
return false, fmt.Errorf("could not decode key: %w", err) | ||
} | ||
|
||
var derivedKey []byte | ||
switch variant { | ||
case "argon2id": | ||
derivedKey = argon2.IDKey([]byte(password), salt, iterations, memory, parallelism, uint32(len(key))) | ||
case "argon2i": | ||
derivedKey = argon2.Key([]byte(password), salt, iterations, memory, parallelism, uint32(len(key))) | ||
default: | ||
return false, fmt.Errorf("unknown variant: %s", variant) | ||
} | ||
|
||
if subtle.ConstantTimeEq(int32(len(key)), int32(len(derivedKey))) == 0 { | ||
return false, nil | ||
} | ||
return subtle.ConstantTimeCompare(key, derivedKey) == 1, nil | ||
} | ||
package argon2 | ||
|
||
import ( | ||
"crypto/rand" | ||
"crypto/subtle" | ||
"encoding/base64" | ||
"errors" | ||
"fmt" | ||
"strings" | ||
|
||
"golang.org/x/crypto/argon2" | ||
) | ||
|
||
// Inspired by https://www.alexedwards.net/blog/how-to-hash-and-verify-passwords-with-argon2-in-go | ||
|
||
// HashPasswordDefault returns hash using argon2id and default parameters | ||
func HashPasswordDefault(password string) (string, error) { | ||
return HashPassword(password, 32, 16, 1, 65536, 2) | ||
} | ||
|
||
// HashPassword returns hash using argon2id and the provided parameters | ||
func HashPassword(password string, keyLength, saltLength, iterations, memory uint32, parallelism uint8) (string, error) { | ||
salt := make([]byte, saltLength) | ||
_, err := rand.Read(salt) | ||
if err != nil { | ||
return "", fmt.Errorf("could not create salt: %w", err) | ||
} | ||
|
||
key := argon2.IDKey([]byte(password), salt, iterations, memory, parallelism, keyLength) | ||
|
||
hash := fmt.Sprintf("$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s", | ||
argon2.Version, | ||
memory, | ||
iterations, | ||
parallelism, | ||
base64.RawStdEncoding.EncodeToString(salt), | ||
base64.RawStdEncoding.EncodeToString(key)) | ||
|
||
return hash, nil | ||
} | ||
|
||
// VerifyPassword checks if password matches the hash, supports argon2id and argon2i | ||
func VerifyPassword(password, hash string) (match bool, err error) { | ||
hashParts := strings.Split(hash, "$") | ||
if len(hashParts) != 6 { | ||
return false, errors.New("invalid hash format") | ||
} | ||
|
||
variant := hashParts[1] | ||
|
||
var version int | ||
_, err = fmt.Sscanf(hashParts[2], "v=%d", &version) | ||
if err != nil { | ||
return false, fmt.Errorf("could not parse version: %w", err) | ||
} | ||
if version != argon2.Version { | ||
return false, fmt.Errorf("incompatible version: %d", version) | ||
} | ||
|
||
var memory uint32 | ||
var iterations uint32 | ||
var parallelism uint8 | ||
|
||
_, err = fmt.Sscanf(hashParts[3], "m=%d,t=%d,p=%d", &memory, &iterations, ¶llelism) | ||
if err != nil { | ||
return false, fmt.Errorf("could not parse parameters: %w", err) | ||
} | ||
|
||
salt, err := base64.RawStdEncoding.Strict().DecodeString(hashParts[4]) | ||
if err != nil { | ||
return false, fmt.Errorf("could not decode salt: %w", err) | ||
} | ||
|
||
key, err := base64.RawStdEncoding.Strict().DecodeString(hashParts[5]) | ||
if err != nil { | ||
return false, fmt.Errorf("could not decode key: %w", err) | ||
} | ||
|
||
var derivedKey []byte | ||
switch variant { | ||
case "argon2id": | ||
derivedKey = argon2.IDKey([]byte(password), salt, iterations, memory, parallelism, uint32(len(key))) | ||
case "argon2i": | ||
derivedKey = argon2.Key([]byte(password), salt, iterations, memory, parallelism, uint32(len(key))) | ||
default: | ||
return false, fmt.Errorf("unknown variant: %s", variant) | ||
} | ||
|
||
if subtle.ConstantTimeEq(int32(len(key)), int32(len(derivedKey))) == 0 { | ||
return false, nil | ||
} | ||
return subtle.ConstantTimeCompare(key, derivedKey) == 1, nil | ||
} |
Oops, something went wrong.