mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2026-07-07 02:30:20 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba18c1bda0 |
+17
-17
@@ -220,23 +220,6 @@ TINYAUTH_LDAP_AUTHCERT=
|
|||||||
TINYAUTH_LDAP_AUTHKEY=
|
TINYAUTH_LDAP_AUTHKEY=
|
||||||
# Cache duration for LDAP group membership in seconds.
|
# Cache duration for LDAP group membership in seconds.
|
||||||
TINYAUTH_LDAP_GROUPCACHETTL=900
|
TINYAUTH_LDAP_GROUPCACHETTL=900
|
||||||
|
|
||||||
# experimental config
|
|
||||||
|
|
||||||
# Enable Tailscale integration.
|
|
||||||
TINYAUTH_EXPERIMENTAL_TAILSCALE_ENABLED=false
|
|
||||||
# Tailscale state directory.
|
|
||||||
TINYAUTH_EXPERIMENTAL_TAILSCALE_DIR="./tailscale_state"
|
|
||||||
# Tailscale hostname.
|
|
||||||
TINYAUTH_EXPERIMENTAL_TAILSCALE_HOSTNAME=
|
|
||||||
# Tailscale auth key.
|
|
||||||
TINYAUTH_EXPERIMENTAL_TAILSCALE_AUTHKEY=
|
|
||||||
# Use ephemeral Tailscale node.
|
|
||||||
TINYAUTH_EXPERIMENTAL_TAILSCALE_EPHEMERAL=false
|
|
||||||
# Enable Tailscale Funnel.
|
|
||||||
TINYAUTH_EXPERIMENTAL_TAILSCALE_FUNNEL=false
|
|
||||||
# Listen on the Tailscale address instead of standard address.
|
|
||||||
TINYAUTH_EXPERIMENTAL_TAILSCALE_LISTEN=false
|
|
||||||
# Label provider to use for ACLs (auto, docker, kubernetes or none to disable). auto detects the environment.
|
# Label provider to use for ACLs (auto, docker, kubernetes or none to disable). auto detects the environment.
|
||||||
TINYAUTH_LABELPROVIDER="auto"
|
TINYAUTH_LABELPROVIDER="auto"
|
||||||
|
|
||||||
@@ -258,3 +241,20 @@ TINYAUTH_LOG_STREAMS_APP_LEVEL=
|
|||||||
TINYAUTH_LOG_STREAMS_AUDIT_ENABLED=false
|
TINYAUTH_LOG_STREAMS_AUDIT_ENABLED=false
|
||||||
# Log level for this stream. Use global if empty.
|
# Log level for this stream. Use global if empty.
|
||||||
TINYAUTH_LOG_STREAMS_AUDIT_LEVEL=
|
TINYAUTH_LOG_STREAMS_AUDIT_LEVEL=
|
||||||
|
|
||||||
|
# tailscale config
|
||||||
|
|
||||||
|
# Enable Tailscale integration.
|
||||||
|
TINYAUTH_TAILSCALE_ENABLED=false
|
||||||
|
# Tailscale state directory.
|
||||||
|
TINYAUTH_TAILSCALE_DIR="./tailscale_state"
|
||||||
|
# Tailscale hostname.
|
||||||
|
TINYAUTH_TAILSCALE_HOSTNAME=
|
||||||
|
# Tailscale auth key.
|
||||||
|
TINYAUTH_TAILSCALE_AUTHKEY=
|
||||||
|
# Use ephemeral Tailscale node.
|
||||||
|
TINYAUTH_TAILSCALE_EPHEMERAL=false
|
||||||
|
# Enable Tailscale Funnel.
|
||||||
|
TINYAUTH_TAILSCALE_FUNNEL=false
|
||||||
|
# Listen on the Tailscale address instead of standard address.
|
||||||
|
TINYAUTH_TAILSCALE_LISTEN=false
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ jobs:
|
|||||||
- name: Check codegen is up to date
|
- name: Check codegen is up to date
|
||||||
run: |
|
run: |
|
||||||
sqlc generate
|
sqlc generate
|
||||||
go generate ./...
|
go generate ./internal/repository/...
|
||||||
git diff --exit-code
|
git diff --exit-code -- internal/repository/
|
||||||
git status --porcelain | grep -q . && echo "untracked files code gen files" && exit 1 || true
|
git status --porcelain -- internal/repository/ | grep -q . && echo "untracked files in internal/repository/" && exit 1 || true
|
||||||
|
|
||||||
- name: Install frontend dependencies
|
- name: Install frontend dependencies
|
||||||
working-directory: ./frontend
|
working-directory: ./frontend
|
||||||
|
|||||||
@@ -35,27 +35,18 @@ jobs:
|
|||||||
VERSION: ${{ steps.metadata.outputs.VERSION }}
|
VERSION: ${{ steps.metadata.outputs.VERSION }}
|
||||||
COMMIT_HASH: ${{ steps.metadata.outputs.COMMIT_HASH }}
|
COMMIT_HASH: ${{ steps.metadata.outputs.COMMIT_HASH }}
|
||||||
BUILD_TIMESTAMP: ${{ steps.metadata.outputs.BUILD_TIMESTAMP }}
|
BUILD_TIMESTAMP: ${{ steps.metadata.outputs.BUILD_TIMESTAMP }}
|
||||||
BUILD_TAGS: ${{ steps.metadata.outputs.BUILD_TAGS }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
ref: nightly
|
ref: nightly
|
||||||
|
|
||||||
- name: Install go
|
|
||||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
|
|
||||||
with:
|
|
||||||
go-version: "^1.26.4"
|
|
||||||
|
|
||||||
- name: Generate metadata
|
- name: Generate metadata
|
||||||
id: metadata
|
id: metadata
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=nightly" >> "$GITHUB_OUTPUT"
|
echo "VERSION=nightly" >> "$GITHUB_OUTPUT"
|
||||||
echo "COMMIT_HASH=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
|
echo "COMMIT_HASH=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
|
||||||
echo "BUILD_TIMESTAMP=$(date '+%Y-%m-%dT%H:%M:%S')" >> "$GITHUB_OUTPUT"
|
echo "BUILD_TIMESTAMP=$(date '+%Y-%m-%dT%H:%M:%S')" >> "$GITHUB_OUTPUT"
|
||||||
export TAILSCALE_BUILD_TAGS=$(go run tailscale.com/cmd/featuretags@v1.100.0 -min -add acme,serve,netstack)
|
|
||||||
export GIN_BUILD_TAGS=nomsgpack
|
|
||||||
echo "BUILD_TAGS=$TAILSCALE_BUILD_TAGS,$GIN_BUILD_TAGS" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
binary-build:
|
binary-build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -92,11 +83,7 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cp -r frontend/dist internal/assets/dist
|
cp -r frontend/dist internal/assets/dist
|
||||||
go build -tags ${{ needs.generate-metadata.outputs.BUILD_TAGS }} \
|
go build -ldflags "-X github.com/tinyauthapp/tinyauth/internal/model.Version=${{ needs.generate-metadata.outputs.VERSION }} -X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-amd64 ./cmd/tinyauth
|
||||||
-ldflags "-X github.com/tinyauthapp/tinyauth/internal/model.Version=${{ needs.generate-metadata.outputs.VERSION }} \
|
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} \
|
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" \
|
|
||||||
-o tinyauth-amd64 ./cmd/tinyauth
|
|
||||||
env:
|
env:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
@@ -141,11 +128,7 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cp -r frontend/dist internal/assets/dist
|
cp -r frontend/dist internal/assets/dist
|
||||||
go build -tags ${{ needs.generate-metadata.outputs.BUILD_TAGS }} \
|
go build -ldflags "-X github.com/tinyauthapp/tinyauth/internal/model.Version=${{ needs.generate-metadata.outputs.VERSION }} -X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-arm64 ./cmd/tinyauth
|
||||||
-ldflags "-X github.com/tinyauthapp/tinyauth/internal/model.Version=${{ needs.generate-metadata.outputs.VERSION }} \
|
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} \
|
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" \
|
|
||||||
-o tinyauth-arm64 ./cmd/tinyauth
|
|
||||||
env:
|
env:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
@@ -183,7 +166,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
|
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
|
||||||
id: build
|
id: build
|
||||||
with:
|
with:
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
@@ -197,7 +180,6 @@ jobs:
|
|||||||
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
||||||
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
||||||
BUILD_TAGS=${{ needs.generate-metadata.outputs.BUILD_TAGS }}
|
|
||||||
|
|
||||||
- name: Export digest
|
- name: Export digest
|
||||||
run: |
|
run: |
|
||||||
@@ -208,7 +190,7 @@ jobs:
|
|||||||
- name: Upload digest
|
- name: Upload digest
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
with:
|
with:
|
||||||
name: digests-alpine-linux-amd64
|
name: digests-linux-amd64
|
||||||
path: ${{ runner.temp }}/digests/*
|
path: ${{ runner.temp }}/digests/*
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
@@ -242,7 +224,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
|
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
|
||||||
id: build
|
id: build
|
||||||
with:
|
with:
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
@@ -257,7 +239,6 @@ jobs:
|
|||||||
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
||||||
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
||||||
BUILD_TAGS=${{ needs.generate-metadata.outputs.BUILD_TAGS }}
|
|
||||||
|
|
||||||
- name: Export digest
|
- name: Export digest
|
||||||
run: |
|
run: |
|
||||||
@@ -301,7 +282,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
|
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
|
||||||
id: build
|
id: build
|
||||||
with:
|
with:
|
||||||
platforms: linux/arm64
|
platforms: linux/arm64
|
||||||
@@ -315,7 +296,6 @@ jobs:
|
|||||||
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
||||||
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
||||||
BUILD_TAGS=${{ needs.generate-metadata.outputs.BUILD_TAGS }}
|
|
||||||
|
|
||||||
- name: Export digest
|
- name: Export digest
|
||||||
run: |
|
run: |
|
||||||
@@ -326,7 +306,7 @@ jobs:
|
|||||||
- name: Upload digest
|
- name: Upload digest
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
with:
|
with:
|
||||||
name: digests-alpine-linux-arm64
|
name: digests-linux-arm64
|
||||||
path: ${{ runner.temp }}/digests/*
|
path: ${{ runner.temp }}/digests/*
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
@@ -360,7 +340,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
|
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
|
||||||
id: build
|
id: build
|
||||||
with:
|
with:
|
||||||
platforms: linux/arm64
|
platforms: linux/arm64
|
||||||
@@ -375,7 +355,6 @@ jobs:
|
|||||||
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
VERSION=${{ needs.generate-metadata.outputs.VERSION }}
|
||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
||||||
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
||||||
BUILD_TAGS=${{ needs.generate-metadata.outputs.BUILD_TAGS }}
|
|
||||||
|
|
||||||
- name: Export digest
|
- name: Export digest
|
||||||
run: |
|
run: |
|
||||||
@@ -401,7 +380,7 @@ jobs:
|
|||||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
with:
|
with:
|
||||||
path: ${{ runner.temp }}/digests
|
path: ${{ runner.temp }}/digests
|
||||||
pattern: digests-alpine-*
|
pattern: digests-*
|
||||||
merge-multiple: true
|
merge-multiple: true
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
|
|||||||
@@ -16,27 +16,16 @@ jobs:
|
|||||||
VERSION: ${{ steps.metadata.outputs.VERSION }}
|
VERSION: ${{ steps.metadata.outputs.VERSION }}
|
||||||
COMMIT_HASH: ${{ steps.metadata.outputs.COMMIT_HASH }}
|
COMMIT_HASH: ${{ steps.metadata.outputs.COMMIT_HASH }}
|
||||||
BUILD_TIMESTAMP: ${{ steps.metadata.outputs.BUILD_TIMESTAMP }}
|
BUILD_TIMESTAMP: ${{ steps.metadata.outputs.BUILD_TIMESTAMP }}
|
||||||
BUILD_TAGS: ${{ steps.metadata.outputs.BUILD_TAGS }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
|
|
||||||
- name: Install go
|
|
||||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
|
|
||||||
with:
|
|
||||||
go-version: "^1.26.4"
|
|
||||||
|
|
||||||
- name: Generate metadata
|
- name: Generate metadata
|
||||||
id: metadata
|
id: metadata
|
||||||
env:
|
|
||||||
REF_NAME: ${{ github.ref_name }}
|
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$REF_NAME" >> "$GITHUB_OUTPUT"
|
echo "VERSION=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
|
||||||
echo "COMMIT_HASH=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
|
echo "COMMIT_HASH=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
|
||||||
echo "BUILD_TIMESTAMP=$(date '+%Y-%m-%dT%H:%M:%S')" >> "$GITHUB_OUTPUT"
|
echo "BUILD_TIMESTAMP=$(date '+%Y-%m-%dT%H:%M:%S')" >> "$GITHUB_OUTPUT"
|
||||||
export TAILSCALE_BUILD_TAGS=$(go run tailscale.com/cmd/featuretags@v1.100.0 -min -add acme,serve,netstack)
|
|
||||||
export GIN_BUILD_TAGS=nomsgpack
|
|
||||||
echo "BUILD_TAGS=$TAILSCALE_BUILD_TAGS,$GIN_BUILD_TAGS" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
binary-build:
|
binary-build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -70,11 +59,7 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cp -r frontend/dist internal/assets/dist
|
cp -r frontend/dist internal/assets/dist
|
||||||
go build -tags ${{ needs.generate-metadata.outputs.BUILD_TAGS }} \
|
go build -ldflags "-s -w -X github.com/tinyauthapp/tinyauth/internal/model.Version=${{ needs.generate-metadata.outputs.VERSION }} -X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-amd64 ./cmd/tinyauth
|
||||||
-ldflags "-s -w -X github.com/tinyauthapp/tinyauth/internal/model.Version=${{ needs.generate-metadata.outputs.VERSION }} \
|
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} \
|
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" \
|
|
||||||
-o tinyauth-amd64 ./cmd/tinyauth
|
|
||||||
env:
|
env:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
@@ -116,11 +101,7 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cp -r frontend/dist internal/assets/dist
|
cp -r frontend/dist internal/assets/dist
|
||||||
go build -tags ${{ needs.generate-metadata.outputs.BUILD_TAGS }} \
|
go build -ldflags "-s -w -X github.com/tinyauthapp/tinyauth/internal/model.Version=${{ needs.generate-metadata.outputs.VERSION }} -X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-arm64 ./cmd/tinyauth
|
||||||
-ldflags "-s -w -X github.com/tinyauthapp/tinyauth/internal/model.Version=${{ needs.generate-metadata.outputs.VERSION }} \
|
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} \
|
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" \
|
|
||||||
-o tinyauth-arm64 ./cmd/tinyauth
|
|
||||||
env:
|
env:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
@@ -155,7 +136,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
|
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
|
||||||
id: build
|
id: build
|
||||||
with:
|
with:
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
@@ -170,7 +151,6 @@ jobs:
|
|||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
||||||
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
||||||
LDFLAGS=-s -w
|
LDFLAGS=-s -w
|
||||||
BUILD_TAGS=${{ needs.generate-metadata.outputs.BUILD_TAGS }}
|
|
||||||
|
|
||||||
- name: Export digest
|
- name: Export digest
|
||||||
run: |
|
run: |
|
||||||
@@ -181,7 +161,7 @@ jobs:
|
|||||||
- name: Upload digest
|
- name: Upload digest
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
with:
|
with:
|
||||||
name: digests-alpine-linux-amd64
|
name: digests-linux-amd64
|
||||||
path: ${{ runner.temp }}/digests/*
|
path: ${{ runner.temp }}/digests/*
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
@@ -212,7 +192,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
|
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
|
||||||
id: build
|
id: build
|
||||||
with:
|
with:
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
@@ -228,7 +208,6 @@ jobs:
|
|||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
||||||
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
||||||
LDFLAGS=-s -w
|
LDFLAGS=-s -w
|
||||||
BUILD_TAGS=${{ needs.generate-metadata.outputs.BUILD_TAGS }}
|
|
||||||
|
|
||||||
- name: Export digest
|
- name: Export digest
|
||||||
run: |
|
run: |
|
||||||
@@ -269,7 +248,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
|
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
|
||||||
id: build
|
id: build
|
||||||
with:
|
with:
|
||||||
platforms: linux/arm64
|
platforms: linux/arm64
|
||||||
@@ -284,7 +263,6 @@ jobs:
|
|||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
||||||
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
||||||
LDFLAGS=-s -w
|
LDFLAGS=-s -w
|
||||||
BUILD_TAGS=${{ needs.generate-metadata.outputs.BUILD_TAGS }}
|
|
||||||
|
|
||||||
- name: Export digest
|
- name: Export digest
|
||||||
run: |
|
run: |
|
||||||
@@ -295,7 +273,7 @@ jobs:
|
|||||||
- name: Upload digest
|
- name: Upload digest
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
with:
|
with:
|
||||||
name: digests-alpine-linux-arm64
|
name: digests-linux-arm64
|
||||||
path: ${{ runner.temp }}/digests/*
|
path: ${{ runner.temp }}/digests/*
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
@@ -326,7 +304,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
|
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
|
||||||
id: build
|
id: build
|
||||||
with:
|
with:
|
||||||
platforms: linux/arm64
|
platforms: linux/arm64
|
||||||
@@ -342,7 +320,6 @@ jobs:
|
|||||||
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
COMMIT_HASH=${{ needs.generate-metadata.outputs.COMMIT_HASH }}
|
||||||
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
BUILD_TIMESTAMP=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}
|
||||||
LDFLAGS=-s -w
|
LDFLAGS=-s -w
|
||||||
BUILD_TAGS=${{ needs.generate-metadata.outputs.BUILD_TAGS }}
|
|
||||||
|
|
||||||
- name: Export digest
|
- name: Export digest
|
||||||
run: |
|
run: |
|
||||||
@@ -368,7 +345,7 @@ jobs:
|
|||||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
with:
|
with:
|
||||||
path: ${{ runner.temp }}/digests
|
path: ${{ runner.temp }}/digests
|
||||||
pattern: digests-alpine-*
|
pattern: digests-*
|
||||||
merge-multiple: true
|
merge-multiple: true
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
|
|||||||
@@ -51,6 +51,3 @@ config.certify.yml
|
|||||||
|
|
||||||
# deepsec
|
# deepsec
|
||||||
/.deepsec
|
/.deepsec
|
||||||
|
|
||||||
# jetbrains
|
|
||||||
/.idea/
|
|
||||||
|
|||||||
+2
-4
@@ -28,7 +28,6 @@ ARG VERSION
|
|||||||
ARG COMMIT_HASH
|
ARG COMMIT_HASH
|
||||||
ARG BUILD_TIMESTAMP
|
ARG BUILD_TIMESTAMP
|
||||||
ARG LDFLAGS
|
ARG LDFLAGS
|
||||||
ARG BUILD_TAGS
|
|
||||||
|
|
||||||
WORKDIR /tinyauth
|
WORKDIR /tinyauth
|
||||||
|
|
||||||
@@ -41,11 +40,10 @@ COPY ./cmd ./cmd
|
|||||||
COPY ./internal ./internal
|
COPY ./internal ./internal
|
||||||
COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
|
COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
|
||||||
|
|
||||||
RUN CGO_ENABLED=0 go build -tags "${BUILD_TAGS}" -ldflags "${LDFLAGS} \
|
RUN CGO_ENABLED=0 go build -ldflags "${LDFLAGS} \
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.Version=${VERSION} \
|
-X github.com/tinyauthapp/tinyauth/internal/model.Version=${VERSION} \
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${COMMIT_HASH} \
|
-X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${COMMIT_HASH} \
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${BUILD_TIMESTAMP}" \
|
-X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${BUILD_TIMESTAMP}" ./cmd/tinyauth
|
||||||
-o tinyauth ./cmd/tinyauth
|
|
||||||
|
|
||||||
# Runner
|
# Runner
|
||||||
FROM alpine:3.24 AS runner
|
FROM alpine:3.24 AS runner
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ ARG VERSION
|
|||||||
ARG COMMIT_HASH
|
ARG COMMIT_HASH
|
||||||
ARG BUILD_TIMESTAMP
|
ARG BUILD_TIMESTAMP
|
||||||
ARG LDFLAGS
|
ARG LDFLAGS
|
||||||
ARG BUILD_TAGS
|
|
||||||
|
|
||||||
WORKDIR /tinyauth
|
WORKDIR /tinyauth
|
||||||
|
|
||||||
@@ -37,15 +36,14 @@ COPY go.sum ./
|
|||||||
|
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
COPY ./cmd ./cmd/
|
COPY ./cmd ./cmd
|
||||||
COPY ./internal ./internal
|
COPY ./internal ./internal
|
||||||
COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
|
COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
|
||||||
|
|
||||||
RUN CGO_ENABLED=0 go build -tags "${BUILD_TAGS}" -ldflags "${LDFLAGS} \
|
RUN CGO_ENABLED=0 go build -ldflags "${LDFLAGS} \
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.Version=${VERSION} \
|
-X github.com/tinyauthapp/tinyauth/internal/model.Version=${VERSION} \
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${COMMIT_HASH} \
|
-X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${COMMIT_HASH} \
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${BUILD_TIMESTAMP}" \
|
-X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${BUILD_TIMESTAMP}" ./cmd/tinyauth
|
||||||
-o tinyauth ./cmd/tinyauth
|
|
||||||
|
|
||||||
# Make the data directory with a non-root user
|
# Make the data directory with a non-root user
|
||||||
RUN addgroup tinyauth && adduser -DH tinyauth -G tinyauth
|
RUN addgroup tinyauth && adduser -DH tinyauth -G tinyauth
|
||||||
|
|||||||
@@ -9,11 +9,6 @@ COMMIT_HASH := $(shell git rev-parse HEAD)
|
|||||||
BUILD_TIMESTAMP := $(shell date '+%Y-%m-%dT%H:%M:%S')
|
BUILD_TIMESTAMP := $(shell date '+%Y-%m-%dT%H:%M:%S')
|
||||||
BIN_NAME := tinyauth-$(GOARCH)
|
BIN_NAME := tinyauth-$(GOARCH)
|
||||||
LDFLAGS := -s -w
|
LDFLAGS := -s -w
|
||||||
# We don't want all of the tailscale feature-set
|
|
||||||
TAILSCALE_BUILD_TAGS = $(shell go run tailscale.com/cmd/featuretags@v1.100.0 -min -add acme,serve,netstack)
|
|
||||||
# Whatever 6MB serialization lib Gin is using
|
|
||||||
GIN_BUILD_TAGS := nomsgpack
|
|
||||||
BUILD_TAGS = $(GIN_BUILD_TAGS),$(TAILSCALE_BUILD_TAGS)
|
|
||||||
|
|
||||||
# Development vars
|
# Development vars
|
||||||
DEV_COMPOSE := $(shell test -f "docker-compose.test.yml" && echo "docker-compose.test.yml" || echo "docker-compose.dev.yml" )
|
DEV_COMPOSE := $(shell test -f "docker-compose.test.yml" && echo "docker-compose.test.yml" || echo "docker-compose.dev.yml" )
|
||||||
@@ -44,7 +39,7 @@ webui: clean-webui
|
|||||||
|
|
||||||
# Build the binary
|
# Build the binary
|
||||||
binary: webui
|
binary: webui
|
||||||
CGO_ENABLED=$(CGO_ENABLED) go build -tags "${BUILD_TAGS}" -ldflags "${LDFLAGS} \
|
CGO_ENABLED=$(CGO_ENABLED) go build -ldflags "${LDFLAGS} \
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.Version=${TAG_NAME} \
|
-X github.com/tinyauthapp/tinyauth/internal/model.Version=${TAG_NAME} \
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${COMMIT_HASH} \
|
-X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${COMMIT_HASH} \
|
||||||
-X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${BUILD_TIMESTAMP}" \
|
-X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${BUILD_TIMESTAMP}" \
|
||||||
@@ -98,22 +93,13 @@ sql:
|
|||||||
|
|
||||||
# Go gen
|
# Go gen
|
||||||
generate:
|
generate:
|
||||||
go generate ./...
|
go run ./gen
|
||||||
|
go generate ./internal/repository/...
|
||||||
|
|
||||||
# Docker image
|
# Docker image
|
||||||
docker:
|
docker:
|
||||||
docker buildx build -t tinyauthapp/tinyauth:dev \
|
docker buildx build -t tinyauthapp/tinyauth:dev --build-arg=VERSION=$(TAG_NAME) --build-arg=COMMIT_HASH=$(COMMIT_HASH) --build-arg=BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) -f Dockerfile .
|
||||||
--build-arg=VERSION=$(TAG_NAME) \
|
|
||||||
--build-arg=COMMIT_HASH=$(COMMIT_HASH) \
|
|
||||||
--build-arg=BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) \
|
|
||||||
--build-arg=BUILD_TAGS=$(BUILD_TAGS) \
|
|
||||||
-f Dockerfile .
|
|
||||||
|
|
||||||
# Docker image distroless
|
# Docker image distroless
|
||||||
docker-distroless:
|
docker-distroless:
|
||||||
docker buildx build -t tinyauthapp/tinyauth:dev-distroless \
|
docker buildx build -t tinyauthapp/tinyauth:dev-distroless --build-arg=VERSION=$(TAG_NAME) --build-arg=COMMIT_HASH=$(COMMIT_HASH) --build-arg=BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) -f Dockerfile.distroless .
|
||||||
--build-arg=VERSION=$(TAG_NAME) \
|
|
||||||
--build-arg=COMMIT_HASH=$(COMMIT_HASH) \
|
|
||||||
--build-arg=BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) \
|
|
||||||
--build-arg=BUILD_TAGS=$(BUILD_TAGS) \
|
|
||||||
-f Dockerfile.distroless .
|
|
||||||
|
|||||||
+5
-11
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/tinyauthapp/paerser/cli"
|
"github.com/tinyauthapp/paerser/cli"
|
||||||
"github.com/tinyauthapp/tinyauth/internal/model"
|
"github.com/tinyauthapp/tinyauth/internal/model"
|
||||||
@@ -11,21 +11,15 @@ import (
|
|||||||
func configCmd(tconfig *model.Config, loaders []cli.ResourceLoader) *cli.Command {
|
func configCmd(tconfig *model.Config, loaders []cli.ResourceLoader) *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "config",
|
Name: "config",
|
||||||
Description: "Dump the current configuration in YAML format, useful for debugging",
|
Description: "Print the configuration of Tinyauth",
|
||||||
Configuration: tconfig,
|
Configuration: tconfig,
|
||||||
Resources: loaders,
|
Resources: loaders,
|
||||||
Run: func(_ []string) error {
|
Run: func(_ []string) error {
|
||||||
buf := strings.Builder{}
|
jsonBytes, err := json.MarshalIndent(tconfig, "", " ")
|
||||||
|
|
||||||
fmt.Fprint(&buf, "Your current configuration in YAML is:\n\n")
|
|
||||||
|
|
||||||
err := renderYamlToBuf(&buf, tconfig)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to render yaml config: %w", err)
|
return fmt.Errorf("failed to marshal configuration: %w", err)
|
||||||
}
|
}
|
||||||
|
fmt.Println(string(jsonBytes))
|
||||||
fmt.Print(buf.String())
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/tinyauthapp/paerser/cli"
|
|
||||||
"github.com/tinyauthapp/tinyauth/internal/model"
|
|
||||||
"github.com/tinyauthapp/tinyauth/internal/utils"
|
"github.com/tinyauthapp/tinyauth/internal/utils"
|
||||||
|
"github.com/tinyauthapp/paerser/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createOidcClientCmd() *cli.Command {
|
func createOidcClientCmd() *cli.Command {
|
||||||
@@ -32,84 +31,40 @@ func createOidcClientCmd() *cli.Command {
|
|||||||
return errors.New("client name can only contain alphanumeric characters and hyphens")
|
return errors.New("client name can only contain alphanumeric characters and hyphens")
|
||||||
}
|
}
|
||||||
|
|
||||||
u := uuid.New()
|
uuid := uuid.New()
|
||||||
clientId := u.String()
|
clientId := uuid.String()
|
||||||
clientSecret := "ta-" + utils.GenerateString(61)
|
clientSecret := "ta-" + utils.GenerateString(61)
|
||||||
|
|
||||||
uclientName := strings.ToUpper(clientName)
|
uclientName := strings.ToUpper(clientName)
|
||||||
lclientName := strings.ToLower(clientName)
|
lclientName := strings.ToLower(clientName)
|
||||||
|
|
||||||
buf := strings.Builder{}
|
builder := strings.Builder{}
|
||||||
|
|
||||||
// header
|
// header
|
||||||
fmt.Fprintf(&buf, "Created '%s' OIDC client.\n\n", clientName)
|
fmt.Fprintf(&builder, "Created credentials for client %s\n\n", clientName)
|
||||||
|
|
||||||
// credentials
|
// credentials
|
||||||
fmt.Fprintf(&buf, "Credentials:\n\n")
|
fmt.Fprintf(&builder, "Client Name: %s\n", clientName)
|
||||||
fmt.Fprintf(&buf, "Client Name: %s\n", clientName)
|
fmt.Fprintf(&builder, "Client ID: %s\n", clientId)
|
||||||
fmt.Fprintf(&buf, "Client ID: %s\n", clientId)
|
fmt.Fprintf(&builder, "Client Secret: %s\n\n", clientSecret)
|
||||||
fmt.Fprintf(&buf, "Client Secret: %s\n\n", clientSecret)
|
|
||||||
|
|
||||||
// end variables
|
// env variables
|
||||||
fmt.Fprintf(&buf, "Environment variables:\n\n")
|
fmt.Fprint(&builder, "Environment variables:\n\n")
|
||||||
renderToBuf(&buf, []kv{
|
fmt.Fprintf(&builder, "TINYAUTH_OIDC_CLIENTS_%s_CLIENTID=%s\n", uclientName, clientId)
|
||||||
{
|
fmt.Fprintf(&builder, "TINYAUTH_OIDC_CLIENTS_%s_CLIENTSECRET=%s\n", uclientName, clientSecret)
|
||||||
k: fmt.Sprintf("TINYAUTH_OIDC_CLIENTS_%s_CLIENTID", uclientName),
|
fmt.Fprintf(&builder, "TINYAUTH_OIDC_CLIENTS_%s_NAME=%s\n\n", uclientName, utils.Capitalize(lclientName))
|
||||||
v: clientId,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
k: fmt.Sprintf("TINYAUTH_OIDC_CLIENTS_%s_CLIENTSECRET", uclientName),
|
|
||||||
v: clientSecret,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
k: fmt.Sprintf("TINYAUTH_OIDC_CLIENTS_%s_NAME", uclientName),
|
|
||||||
v: utils.Capitalize(lclientName),
|
|
||||||
},
|
|
||||||
}, "=")
|
|
||||||
fmt.Fprintf(&buf, "\n")
|
|
||||||
|
|
||||||
// cli flags
|
// cli flags
|
||||||
fmt.Fprintf(&buf, "CLI flags:\n\n")
|
fmt.Fprint(&builder, "CLI flags:\n\n")
|
||||||
renderToBuf(&buf, []kv{
|
fmt.Fprintf(&builder, "--oidc.clients.%s.clientid=%s\n", lclientName, clientId)
|
||||||
{
|
fmt.Fprintf(&builder, "--oidc.clients.%s.clientsecret=%s\n", lclientName, clientSecret)
|
||||||
k: fmt.Sprintf("--oidc.clients.%s.clientid", lclientName),
|
fmt.Fprintf(&builder, "--oidc.clients.%s.name=%s\n\n", lclientName, utils.Capitalize(lclientName))
|
||||||
v: clientId,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
k: fmt.Sprintf("--oidc.clients.%s.clientsecret", lclientName),
|
|
||||||
v: clientSecret,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
k: fmt.Sprintf("--oidc.clients.%s.name", lclientName),
|
|
||||||
v: utils.Capitalize(lclientName),
|
|
||||||
},
|
|
||||||
}, "=")
|
|
||||||
fmt.Fprintf(&buf, "\n")
|
|
||||||
|
|
||||||
// yaml config
|
|
||||||
fmt.Fprintf(&buf, "YAML config:\n\n")
|
|
||||||
|
|
||||||
err = renderYamlToBuf(&buf, &model.OIDCConfig{
|
|
||||||
Clients: map[string]model.OIDCClientConfig{
|
|
||||||
lclientName: {
|
|
||||||
ClientID: clientId,
|
|
||||||
ClientSecret: clientSecret,
|
|
||||||
Name: utils.Capitalize(lclientName),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to render yaml config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.WriteString("\n")
|
|
||||||
|
|
||||||
// footer
|
// footer
|
||||||
fmt.Fprintln(&buf, "You can use any of the above options to configure your OIDC client. Make sure to save these credentials as there is no way to regenerate them.")
|
fmt.Fprintln(&builder, "You can use either option to configure your OIDC client. Make sure to save these credentials as there is no way to regenerate them.")
|
||||||
|
|
||||||
// print
|
// print
|
||||||
out := buf.String()
|
out := builder.String()
|
||||||
fmt.Print(out)
|
fmt.Print(out)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|||||||
+15
-61
@@ -3,12 +3,11 @@ package main
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"charm.land/huh/v2"
|
"charm.land/huh/v2"
|
||||||
"github.com/tinyauthapp/paerser/cli"
|
"github.com/tinyauthapp/paerser/cli"
|
||||||
"github.com/tinyauthapp/tinyauth/internal/model"
|
"github.com/tinyauthapp/tinyauth/internal/utils/logger"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,107 +34,62 @@ func createUserCmd() *cli.Command {
|
|||||||
&cli.FlagLoader{},
|
&cli.FlagLoader{},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := &cli.Command{
|
return &cli.Command{
|
||||||
Name: "create",
|
Name: "create",
|
||||||
Description: "Create a user",
|
Description: "Create a user",
|
||||||
Configuration: tCfg,
|
Configuration: tCfg,
|
||||||
Resources: loaders,
|
Resources: loaders,
|
||||||
}
|
Run: func(_ []string) error {
|
||||||
|
log := logger.NewLogger().WithSimpleConfig()
|
||||||
|
log.Init()
|
||||||
|
|
||||||
cmd.Run = func(_ []string) error {
|
|
||||||
if tCfg.Interactive {
|
if tCfg.Interactive {
|
||||||
form := huh.NewForm(
|
form := huh.NewForm(
|
||||||
huh.NewGroup(
|
huh.NewGroup(
|
||||||
huh.NewInput().Title("Username").Value(&tCfg.Username).Validate(func(s string) error {
|
huh.NewInput().Title("Username").Value(&tCfg.Username).Validate((func(s string) error {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return errors.New("username cannot be empty")
|
return errors.New("username cannot be empty")
|
||||||
}
|
}
|
||||||
if strings.Contains(s, ":") {
|
|
||||||
return errors.New("username cannot contain ':'")
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}),
|
})),
|
||||||
huh.NewInput().Title("Password").Value(&tCfg.Password).Validate(func(s string) error {
|
huh.NewInput().Title("Password").Value(&tCfg.Password).Validate((func(s string) error {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return errors.New("password cannot be empty")
|
return errors.New("password cannot be empty")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}),
|
})),
|
||||||
huh.NewSelect[bool]().Title("Format the output for Docker?").Options(huh.NewOption("Yes", true), huh.NewOption("No", false)).Value(&tCfg.Docker),
|
huh.NewSelect[bool]().Title("Format the output for Docker?").Options(huh.NewOption("Yes", true), huh.NewOption("No", false)).Value(&tCfg.Docker),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
theme := new(themeBase)
|
theme := new(themeBase)
|
||||||
|
|
||||||
err := form.WithTheme(theme).Run()
|
err := form.WithTheme(theme).Run()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to run interactive prompt: %w", err)
|
return fmt.Errorf("failed to run interactive prompt: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if tCfg.Username == "" || tCfg.Password == "" {
|
if tCfg.Username == "" || tCfg.Password == "" {
|
||||||
cmd.PrintHelp(os.Stdout)
|
|
||||||
return errors.New("username and password cannot be empty")
|
return errors.New("username and password cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(tCfg.Username, ":") {
|
log.App.Info().Str("username", tCfg.Username).Msg("Creating user")
|
||||||
return errors.New("username cannot contain ':'")
|
|
||||||
}
|
|
||||||
|
|
||||||
passwd, err := bcrypt.GenerateFromPassword([]byte(tCfg.Password), bcrypt.DefaultCost)
|
passwd, err := bcrypt.GenerateFromPassword([]byte(tCfg.Password), bcrypt.DefaultCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to hash password: %w", err)
|
return fmt.Errorf("failed to hash password: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only the docker compose output needs $ escaped, the raw hash is correct everywhere else
|
// If docker format is enabled, escape the dollar sign
|
||||||
passwdStr := string(passwd)
|
passwdStr := string(passwd)
|
||||||
outputStr := passwdStr
|
|
||||||
|
|
||||||
if tCfg.Docker {
|
if tCfg.Docker {
|
||||||
outputStr = strings.ReplaceAll(passwdStr, "$", "$$")
|
passwdStr = strings.ReplaceAll(passwdStr, "$", "$$")
|
||||||
}
|
}
|
||||||
|
|
||||||
user := fmt.Sprintf("%s:%s", tCfg.Username, passwdStr)
|
log.App.Info().Str("user", fmt.Sprintf("%s:%s", tCfg.Username, passwdStr)).Msg("User created")
|
||||||
escapedUser := fmt.Sprintf("%s:%s", tCfg.Username, outputStr)
|
|
||||||
|
|
||||||
buf := strings.Builder{}
|
|
||||||
|
|
||||||
// header
|
|
||||||
fmt.Fprintf(&buf, "Created user '%s'.\n\n", tCfg.Username)
|
|
||||||
|
|
||||||
// environment variable
|
|
||||||
fmt.Fprint(&buf, "Environment variable:\n\n")
|
|
||||||
renderToBuf(&buf, []kv{
|
|
||||||
{"TINYAUTH_AUTH_USERS", escapedUser},
|
|
||||||
}, "=")
|
|
||||||
|
|
||||||
// cli flags
|
|
||||||
fmt.Fprint(&buf, "\nCLI flags:\n\n")
|
|
||||||
renderToBuf(&buf, []kv{
|
|
||||||
{"--auth.users", user},
|
|
||||||
}, "=")
|
|
||||||
|
|
||||||
// yaml config
|
|
||||||
fmt.Fprint(&buf, "\nYAML config:\n\n")
|
|
||||||
|
|
||||||
err = renderYamlToBuf(&buf, &model.Config{
|
|
||||||
Auth: model.AuthConfig{
|
|
||||||
Users: []string{user},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to render yaml config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.WriteString("\n")
|
|
||||||
|
|
||||||
// footer
|
|
||||||
fmt.Fprint(&buf, "Use your config option of choice to add the user to Tinyauth and then restart.")
|
|
||||||
|
|
||||||
fmt.Println(buf.String())
|
|
||||||
return nil
|
return nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tinyauthapp/tinyauth/internal/utils"
|
"github.com/tinyauthapp/tinyauth/internal/utils"
|
||||||
|
"github.com/tinyauthapp/tinyauth/internal/utils/logger"
|
||||||
|
|
||||||
"charm.land/huh/v2"
|
"charm.land/huh/v2"
|
||||||
"github.com/mdp/qrterminal/v3"
|
"github.com/mdp/qrterminal/v3"
|
||||||
@@ -33,15 +34,14 @@ func generateTotpCmd() *cli.Command {
|
|||||||
&cli.FlagLoader{},
|
&cli.FlagLoader{},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := &cli.Command{
|
return &cli.Command{
|
||||||
Name: "generate",
|
Name: "generate",
|
||||||
Description: "Generate a TOTP secret",
|
Description: "Generate a TOTP secret",
|
||||||
Configuration: tCfg,
|
Configuration: tCfg,
|
||||||
Resources: loaders,
|
Resources: loaders,
|
||||||
}
|
Run: func(_ []string) error {
|
||||||
|
log := logger.NewLogger().WithSimpleConfig()
|
||||||
cmd.Run = func(_ []string) error {
|
log.Init()
|
||||||
colors := getColors()
|
|
||||||
|
|
||||||
if tCfg.Interactive {
|
if tCfg.Interactive {
|
||||||
form := huh.NewForm(
|
form := huh.NewForm(
|
||||||
@@ -63,11 +63,6 @@ func generateTotpCmd() *cli.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if tCfg.User == "" {
|
|
||||||
cmd.PrintHelp(os.Stdout)
|
|
||||||
return fmt.Errorf("user is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := utils.ParseUser(tCfg.User)
|
user, err := utils.ParseUser(tCfg.User)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -94,7 +89,9 @@ func generateTotpCmd() *cli.Command {
|
|||||||
|
|
||||||
secret := key.Secret()
|
secret := key.Secret()
|
||||||
|
|
||||||
fmt.Printf("Scan the following QR code with your authenticator app (e.g., Google Authenticator, 2fauth, Microsoft Authenticator):\n\n")
|
log.App.Info().Str("secret", secret).Msg("Generated TOTP secret")
|
||||||
|
|
||||||
|
log.App.Info().Msg("Generated QR code")
|
||||||
|
|
||||||
config := qrterminal.Config{
|
config := qrterminal.Config{
|
||||||
Level: qrterminal.L,
|
Level: qrterminal.L,
|
||||||
@@ -113,18 +110,9 @@ func generateTotpCmd() *cli.Command {
|
|||||||
user.Password = strings.ReplaceAll(user.Password, "$", "$$")
|
user.Password = strings.ReplaceAll(user.Password, "$", "$$")
|
||||||
}
|
}
|
||||||
|
|
||||||
userStr := fmt.Sprintf("%s:%s:%s", user.Username, user.Password, user.TOTPSecret)
|
log.App.Info().Str("user", fmt.Sprintf("%s:%s:%s", user.Username, user.Password, user.TOTPSecret)).Msg("Add the totp secret to your authenticator app then use the verify command to ensure everything is working correctly.")
|
||||||
|
|
||||||
fmt.Print("\nOr add the following TOTP secret to your authenticator app: ")
|
|
||||||
fmt.Print(colors.green.Render(secret))
|
|
||||||
fmt.Print("\n\n")
|
|
||||||
|
|
||||||
fmt.Printf("Finally, add your user '%s' back to your configuration: ", user.Username)
|
|
||||||
fmt.Print(colors.green.Render(userStr))
|
|
||||||
fmt.Print("\n")
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-140
@@ -2,17 +2,13 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"charm.land/huh/v2"
|
"charm.land/huh/v2"
|
||||||
"charm.land/lipgloss/v2"
|
|
||||||
"github.com/tinyauthapp/tinyauth/internal/bootstrap"
|
"github.com/tinyauthapp/tinyauth/internal/bootstrap"
|
||||||
"github.com/tinyauthapp/tinyauth/internal/model"
|
"github.com/tinyauthapp/tinyauth/internal/model"
|
||||||
"github.com/tinyauthapp/tinyauth/internal/utils/loaders"
|
"github.com/tinyauthapp/tinyauth/internal/utils/loaders"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/tinyauthapp/paerser/cli"
|
"github.com/tinyauthapp/paerser/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,114 +28,89 @@ func main() {
|
|||||||
Configuration: tConfig,
|
Configuration: tConfig,
|
||||||
Resources: loaders,
|
Resources: loaders,
|
||||||
Run: func(_ []string) error {
|
Run: func(_ []string) error {
|
||||||
if !reflect.DeepEqual(model.NewDefaultConfiguration(env).Experimental, tConfig.Experimental) {
|
|
||||||
colors := getColors()
|
|
||||||
fmt.Println(colors.yellow.Render("⚠") + " Experimental features are enabled, use with caution. Experimental features may change with each release.")
|
|
||||||
}
|
|
||||||
return runCmd(*tConfig)
|
return runCmd(*tConfig)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdUser := &cli.Command{
|
cmdUser := &cli.Command{
|
||||||
Name: "user",
|
Name: "user",
|
||||||
Description: "Manage users",
|
Description: "Manage Tinyauth users",
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdTotp := &cli.Command{
|
cmdTotp := &cli.Command{
|
||||||
Name: "totp",
|
Name: "totp",
|
||||||
Description: "Manage TOTP users",
|
Description: "Manage Tinyauth TOTP users",
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdOidc := &cli.Command{
|
cmdOidc := &cli.Command{
|
||||||
Name: "oidc",
|
Name: "oidc",
|
||||||
Description: "Manage OIDC clients",
|
Description: "Manage Tinyauth OIDC clients",
|
||||||
}
|
}
|
||||||
|
|
||||||
helpCmd := &cli.Command{
|
err := cmdTinyauth.AddCommand(versionCmd())
|
||||||
Name: "help",
|
|
||||||
Description: "Show the help message",
|
|
||||||
Run: func(_ []string) error {
|
|
||||||
return cmdTinyauth.PrintHelp(os.Stdout)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
err := cmdTinyauth.AddCommand(helpCmd)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf(err, "Failed to add help command")
|
log.Fatal().Err(err).Msg("Failed to add version command")
|
||||||
}
|
|
||||||
|
|
||||||
err = cmdTinyauth.AddCommand(versionCmd())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fatalf(err, "Failed to add version command")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmdTinyauth.AddCommand(configCmd(tConfig, loaders))
|
err = cmdTinyauth.AddCommand(configCmd(tConfig, loaders))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf(err, "Failed to add config command")
|
log.Fatal().Err(err).Msg("Failed to add config command")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmdUser.AddCommand(verifyUserCmd())
|
err = cmdUser.AddCommand(verifyUserCmd())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf(err, "Failed to add user verify command")
|
log.Fatal().Err(err).Msg("Failed to add verify command")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmdTinyauth.AddCommand(healthcheckCmd())
|
err = cmdTinyauth.AddCommand(healthcheckCmd())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf(err, "Failed to add healthcheck command")
|
log.Fatal().Err(err).Msg("Failed to add healthcheck command")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmdTotp.AddCommand(generateTotpCmd())
|
err = cmdTotp.AddCommand(generateTotpCmd())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf(err, "Failed to add totp generate command")
|
log.Fatal().Err(err).Msg("Failed to add generate command")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmdUser.AddCommand(createUserCmd())
|
err = cmdUser.AddCommand(createUserCmd())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf(err, "Failed to add create user command")
|
log.Fatal().Err(err).Msg("Failed to add create command")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmdOidc.AddCommand(createOidcClientCmd())
|
err = cmdOidc.AddCommand(createOidcClientCmd())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf(err, "Failed to add create oidc client command")
|
log.Fatal().Err(err).Msg("Failed to add create command")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmdTinyauth.AddCommand(cmdUser)
|
err = cmdTinyauth.AddCommand(cmdUser)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf(err, "Failed to add user command")
|
log.Fatal().Err(err).Msg("Failed to add user command")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmdTinyauth.AddCommand(cmdTotp)
|
err = cmdTinyauth.AddCommand(cmdTotp)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf(err, "Failed to add totp command")
|
log.Fatal().Err(err).Msg("Failed to add totp command")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmdTinyauth.AddCommand(cmdOidc)
|
err = cmdTinyauth.AddCommand(cmdOidc)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf(err, "Failed to add oidc command")
|
log.Fatal().Err(err).Msg("Failed to add oidc command")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cli.Execute(cmdTinyauth)
|
err = cli.Execute(cmdTinyauth)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "command not found") {
|
log.Fatal().Err(err).Msg("Failed to execute command")
|
||||||
fmt.Println("Command not found. Use 'tinyauth help' to see available commands.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if strings.Contains(err.Error(), "is not runnable") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fatalf(err, "Failed to execute command")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,98 +131,3 @@ type themeBase struct{}
|
|||||||
func (t *themeBase) Theme(isDark bool) *huh.Styles {
|
func (t *themeBase) Theme(isDark bool) *huh.Styles {
|
||||||
return huh.ThemeBase(isDark)
|
return huh.ThemeBase(isDark)
|
||||||
}
|
}
|
||||||
|
|
||||||
type colors struct {
|
|
||||||
blue lipgloss.Style
|
|
||||||
gray lipgloss.Style
|
|
||||||
lightGray lipgloss.Style
|
|
||||||
green lipgloss.Style
|
|
||||||
yellow lipgloss.Style
|
|
||||||
}
|
|
||||||
|
|
||||||
func getColors() colors {
|
|
||||||
noColor := os.Getenv("NO_COLOR")
|
|
||||||
forceColor := os.Getenv("FORCE_COLOR")
|
|
||||||
|
|
||||||
colorOut := colors{
|
|
||||||
green: lipgloss.NewStyle().Foreground(lipgloss.ANSIColor(34)),
|
|
||||||
gray: lipgloss.NewStyle().Foreground(lipgloss.ANSIColor(245)),
|
|
||||||
yellow: lipgloss.NewStyle().Foreground(lipgloss.ANSIColor(214)),
|
|
||||||
blue: lipgloss.NewStyle().Foreground(lipgloss.ANSIColor(75)),
|
|
||||||
lightGray: lipgloss.NewStyle().Foreground(lipgloss.ANSIColor(250)),
|
|
||||||
}
|
|
||||||
|
|
||||||
noColorOut := colors{
|
|
||||||
green: lipgloss.NewStyle(),
|
|
||||||
gray: lipgloss.NewStyle(),
|
|
||||||
yellow: lipgloss.NewStyle(),
|
|
||||||
blue: lipgloss.NewStyle(),
|
|
||||||
lightGray: lipgloss.NewStyle(),
|
|
||||||
}
|
|
||||||
|
|
||||||
useColors := true
|
|
||||||
|
|
||||||
if noColor == "true" || noColor == "1" {
|
|
||||||
useColors = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if forceColor == "true" || forceColor == "1" {
|
|
||||||
useColors = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !useColors {
|
|
||||||
return noColorOut
|
|
||||||
}
|
|
||||||
|
|
||||||
return colorOut
|
|
||||||
}
|
|
||||||
|
|
||||||
func fatalf(err error, msg string) {
|
|
||||||
fmt.Printf("%s: %v\n", msg, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
type kv struct {
|
|
||||||
k string
|
|
||||||
v string
|
|
||||||
}
|
|
||||||
|
|
||||||
func renderToBuf(buf *strings.Builder, kv []kv, sep string) {
|
|
||||||
colors := getColors()
|
|
||||||
for _, i := range kv {
|
|
||||||
buf.WriteString(colors.blue.Render(i.k))
|
|
||||||
buf.WriteString(colors.gray.Render(sep))
|
|
||||||
buf.WriteString(colors.lightGray.Render(i.v))
|
|
||||||
buf.WriteString("\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func renderYamlToBuf(buf *strings.Builder, i any) error {
|
|
||||||
colors := getColors()
|
|
||||||
|
|
||||||
yout, err := yaml.Marshal(i)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to marshal yaml: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for l := range strings.SplitSeq(string(yout), "\n") {
|
|
||||||
if l == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(strings.TrimLeft(l, " "), "- ") {
|
|
||||||
buf.WriteString(colors.lightGray.Render(l))
|
|
||||||
buf.WriteString("\n")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
lp := strings.SplitN(l, ":", 2)
|
|
||||||
buf.WriteString(colors.blue.Render(lp[0]))
|
|
||||||
buf.WriteString(colors.gray.Render(":"))
|
|
||||||
if len(lp) == 2 {
|
|
||||||
buf.WriteString(colors.lightGray.Render(lp[1]))
|
|
||||||
}
|
|
||||||
buf.WriteString("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
+10
-16
@@ -3,9 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/tinyauthapp/tinyauth/internal/utils"
|
"github.com/tinyauthapp/tinyauth/internal/utils"
|
||||||
|
"github.com/tinyauthapp/tinyauth/internal/utils/logger"
|
||||||
|
|
||||||
"charm.land/huh/v2"
|
"charm.land/huh/v2"
|
||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
@@ -38,15 +38,14 @@ func verifyUserCmd() *cli.Command {
|
|||||||
&cli.FlagLoader{},
|
&cli.FlagLoader{},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := &cli.Command{
|
return &cli.Command{
|
||||||
Name: "verify",
|
Name: "verify",
|
||||||
Description: "Verify a user is set up correctly",
|
Description: "Verify a user is set up correctly",
|
||||||
Configuration: tCfg,
|
Configuration: tCfg,
|
||||||
Resources: loaders,
|
Resources: loaders,
|
||||||
}
|
Run: func(_ []string) error {
|
||||||
|
log := logger.NewLogger().WithSimpleConfig()
|
||||||
cmd.Run = func(_ []string) error {
|
log.Init()
|
||||||
colors := getColors()
|
|
||||||
|
|
||||||
if tCfg.Interactive {
|
if tCfg.Interactive {
|
||||||
form := huh.NewForm(
|
form := huh.NewForm(
|
||||||
@@ -81,11 +80,6 @@ func verifyUserCmd() *cli.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if tCfg.User == "" || tCfg.Username == "" || tCfg.Password == "" {
|
|
||||||
cmd.PrintHelp(os.Stdout)
|
|
||||||
return fmt.Errorf("user, username, and password are required")
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := utils.ParseUser(tCfg.User)
|
user, err := utils.ParseUser(tCfg.User)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -104,21 +98,21 @@ func verifyUserCmd() *cli.Command {
|
|||||||
|
|
||||||
if user.TOTPSecret == "" {
|
if user.TOTPSecret == "" {
|
||||||
if tCfg.Totp != "" {
|
if tCfg.Totp != "" {
|
||||||
fmt.Println(colors.yellow.Render("⚠") + " TOTP code provided but user does not have TOTP enabled")
|
log.App.Warn().Msg("User does not have TOTP secret")
|
||||||
}
|
}
|
||||||
fmt.Println(colors.green.Render("✓") + " User verified")
|
log.App.Info().Msg("User verified")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := totp.Validate(tCfg.Totp, user.TOTPSecret)
|
ok := totp.Validate(tCfg.Totp, user.TOTPSecret)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("TOTP code incorrect")
|
return fmt.Errorf("TOTP code incorrect")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(colors.green.Render("✓") + " User verified")
|
log.App.Info().Msg("User verified")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,9 @@ func versionCmd() *cli.Command {
|
|||||||
Configuration: nil,
|
Configuration: nil,
|
||||||
Resources: nil,
|
Resources: nil,
|
||||||
Run: func(_ []string) error {
|
Run: func(_ []string) error {
|
||||||
colors := getColors()
|
fmt.Printf("Version: %s\n", model.Version)
|
||||||
fmt.Printf("Version: %s\n", colors.blue.Render(model.Version))
|
fmt.Printf("Commit Hash: %s\n", model.CommitHash)
|
||||||
fmt.Printf("Commit Hash: %s\n", colors.blue.Render(model.CommitHash))
|
fmt.Printf("Build Timestamp: %s\n", model.BuildTimestamp)
|
||||||
fmt.Printf("Build Timestamp: %s\n", colors.blue.Render(model.BuildTimestamp))
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-25
@@ -12,49 +12,50 @@
|
|||||||
},
|
},
|
||||||
"packageManager": "pnpm@11.1.2",
|
"packageManager": "pnpm@11.1.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^5.4.0",
|
"@hookform/resolvers": "^5.2.2",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.19",
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||||
"@radix-ui/react-label": "^2.1.11",
|
"@radix-ui/react-label": "^2.1.8",
|
||||||
"@radix-ui/react-select": "^2.3.2",
|
"@radix-ui/react-select": "^2.2.6",
|
||||||
"@radix-ui/react-separator": "^1.1.11",
|
"@radix-ui/react-separator": "^1.1.8",
|
||||||
"@radix-ui/react-slot": "^1.3.0",
|
"@radix-ui/react-slot": "^1.2.4",
|
||||||
"@tailwindcss/vite": "^4.3.2",
|
"@tailwindcss/vite": "^4.2.2",
|
||||||
"@tanstack/react-query": "^5.101.2",
|
"@tanstack/react-query": "^5.99.0",
|
||||||
"axios": "^1.18.1",
|
"axios": "^1.15.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"i18next": "^26.3.4",
|
"i18next": "^26.0.4",
|
||||||
"i18next-browser-languagedetector": "^8.2.1",
|
"i18next-browser-languagedetector": "^8.2.1",
|
||||||
"i18next-resources-to-backend": "^1.2.1",
|
"i18next-resources-to-backend": "^1.2.1",
|
||||||
"lucide-react": "^1.23.0",
|
"lucide-react": "^1.8.0",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"radix-ui": "^1.6.1",
|
"radix-ui": "^1.4.3",
|
||||||
"react": "^19.2.7",
|
"react": "^19.2.5",
|
||||||
"react-dom": "^19.2.7",
|
"react-dom": "^19.2.5",
|
||||||
"react-hook-form": "^7.81.0",
|
"react-hook-form": "^7.72.1",
|
||||||
"react-i18next": "^17.0.8",
|
"react-i18next": "^17.0.2",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"react-router": "^7.14.0",
|
"react-router": "^7.14.0",
|
||||||
"sonner": "^2.0.7",
|
"sonner": "^2.0.7",
|
||||||
"tailwind-merge": "^3.5.0",
|
"tailwind-merge": "^3.5.0",
|
||||||
"tailwindcss": "^4.3.2",
|
"tailwindcss": "^4.2.2",
|
||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@tanstack/eslint-plugin-query": "^5.101.2",
|
"@tanstack/eslint-plugin-query": "^5.99.0",
|
||||||
"@types/node": "^25.6.0",
|
"@types/node": "^25.6.0",
|
||||||
"@types/react": "^19.2.17",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@vitejs/plugin-react": "^6.0.3",
|
"@vitejs/plugin-react": "^6.0.1",
|
||||||
"eslint": "^10.6.0",
|
"eslint": "^10.2.0",
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
"eslint-plugin-react-refresh": "^0.5.3",
|
"eslint-plugin-react-refresh": "^0.5.2",
|
||||||
"globals": "^17.7.0",
|
"globals": "^17.5.0",
|
||||||
|
"prettier": "3.8.2",
|
||||||
"rollup-plugin-visualizer": "^7.0.1",
|
"rollup-plugin-visualizer": "^7.0.1",
|
||||||
"tw-animate-css": "^1.4.0",
|
"tw-animate-css": "^1.4.0",
|
||||||
"typescript": "~6.0.2",
|
"typescript": "~6.0.2",
|
||||||
"typescript-eslint": "^8.62.1",
|
"typescript-eslint": "^8.58.1",
|
||||||
"vite": "^8.1.3"
|
"vite": "^8.0.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+1377
-1289
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,4 @@
|
|||||||
dangerouslyAllowAllBuilds: false
|
dangerouslyAllowAllBuilds: false
|
||||||
blockExoticSubdeps: true
|
blockExoticSubdeps: true
|
||||||
minimumReleaseAge: 1440 # 1 day
|
minimumReleaseAge: 1440 # 1 day
|
||||||
|
trustPolicy: no-downgrade
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// gen/sqlc_wrapper generates store.go wrapper files for each sqlc driver package under
|
// gen/sqlc-wrapper generates store.go wrapper files for each sqlc driver package under
|
||||||
// internal/repository/<driver>/. Run via:
|
// internal/repository/<driver>/. Run via:
|
||||||
//
|
//
|
||||||
// go generate ./internal/repository/...
|
// go generate ./internal/repository/...
|
||||||
@@ -32,7 +32,7 @@ import (
|
|||||||
var storeSrc string
|
var storeSrc string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println("sqlc_wrapper: generating store.go files for sqlc driver packages...")
|
fmt.Println("sqlc-wrapper: generating store.go files for sqlc driver packages...")
|
||||||
if err := run(); err != nil {
|
if err := run(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
package tinyauth
|
|
||||||
|
|
||||||
//go:generate go run github.com/tinyauthapp/tinyauth/gen/docs
|
|
||||||
@@ -4,7 +4,6 @@ go 1.26.4
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
charm.land/huh/v2 v2.0.3
|
charm.land/huh/v2 v2.0.3
|
||||||
charm.land/lipgloss/v2 v2.0.1
|
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3
|
github.com/cenkalti/backoff/v5 v5.0.3
|
||||||
github.com/docker/docker v28.5.2+incompatible
|
github.com/docker/docker v28.5.2+incompatible
|
||||||
github.com/gin-gonic/gin v1.12.0
|
github.com/gin-gonic/gin v1.12.0
|
||||||
@@ -26,7 +25,6 @@ require (
|
|||||||
golang.org/x/crypto v0.53.0
|
golang.org/x/crypto v0.53.0
|
||||||
golang.org/x/oauth2 v0.36.0
|
golang.org/x/oauth2 v0.36.0
|
||||||
golang.org/x/tools v0.47.0
|
golang.org/x/tools v0.47.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
|
||||||
k8s.io/apimachinery v0.36.2
|
k8s.io/apimachinery v0.36.2
|
||||||
k8s.io/client-go v0.36.2
|
k8s.io/client-go v0.36.2
|
||||||
modernc.org/sqlite v1.53.0
|
modernc.org/sqlite v1.53.0
|
||||||
@@ -36,6 +34,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
charm.land/bubbles/v2 v2.0.0 // indirect
|
charm.land/bubbles/v2 v2.0.0 // indirect
|
||||||
charm.land/bubbletea/v2 v2.0.2 // indirect
|
charm.land/bubbletea/v2 v2.0.2 // indirect
|
||||||
|
charm.land/lipgloss/v2 v2.0.1 // indirect
|
||||||
dario.cat/mergo v1.0.1 // indirect
|
dario.cat/mergo v1.0.1 // indirect
|
||||||
filippo.io/edwards25519 v1.2.0 // indirect
|
filippo.io/edwards25519 v1.2.0 // indirect
|
||||||
github.com/Azure/go-ntlmssp v0.1.1 // indirect
|
github.com/Azure/go-ntlmssp v0.1.1 // indirect
|
||||||
@@ -170,6 +169,7 @@ require (
|
|||||||
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
|
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
|
||||||
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect
|
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
gotest.tools/v3 v3.5.2 // indirect
|
gotest.tools/v3 v3.5.2 // indirect
|
||||||
gvisor.dev/gvisor v0.0.0-20260224225140-573d5e7127a8 // indirect
|
gvisor.dev/gvisor v0.0.0-20260224225140-573d5e7127a8 // indirect
|
||||||
k8s.io/klog/v2 v2.140.0 // indirect
|
k8s.io/klog/v2 v2.140.0 // indirect
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ func (app *BootstrapApp) Setup() error {
|
|||||||
app.runtime.ConfiguredProviders = configuredProviders
|
app.runtime.ConfiguredProviders = configuredProviders
|
||||||
|
|
||||||
// if tailscale is enabled and listening, replace the app url with the tailscale hostname
|
// if tailscale is enabled and listening, replace the app url with the tailscale hostname
|
||||||
if app.services.tailscaleService != nil && app.config.Experimental.Tailscale.Listen {
|
if app.services.tailscaleService != nil && app.config.Tailscale.Listen {
|
||||||
tailscaleUrl := "https://" + app.services.tailscaleService.GetHostname()
|
tailscaleUrl := "https://" + app.services.tailscaleService.GetHostname()
|
||||||
|
|
||||||
// if the tailscale url is different from the app url, replace it
|
// if the tailscale url is different from the app url, replace it
|
||||||
|
|||||||
@@ -130,9 +130,9 @@ func (app *BootstrapApp) setupRouter() error {
|
|||||||
// 2. Unix socket (if server.socketPath)
|
// 2. Unix socket (if server.socketPath)
|
||||||
// 3. HTTP - default
|
// 3. HTTP - default
|
||||||
func (app *BootstrapApp) getListenerFunc() (func(ctx context.Context) error, error) {
|
func (app *BootstrapApp) getListenerFunc() (func(ctx context.Context) error, error) {
|
||||||
if app.config.Experimental.Tailscale.Listen {
|
if app.config.Tailscale.Listen {
|
||||||
if app.services.tailscaleService == nil {
|
if app.services.tailscaleService == nil {
|
||||||
return nil, fmt.Errorf("experimental.tailscale.listen is enabled but tailscale service is not initialized")
|
return nil, fmt.Errorf("tailscale.listen is enabled but tailscale service is not initialized")
|
||||||
}
|
}
|
||||||
return app.serveTailscale, nil
|
return app.serveTailscale, nil
|
||||||
}
|
}
|
||||||
@@ -227,6 +227,7 @@ func (app *BootstrapApp) serve(listener net.Listener, server *http.Server, ctx c
|
|||||||
err := server.Serve(listener)
|
err := server.Serve(listener)
|
||||||
|
|
||||||
if err != nil && !errors.Is(err, http.ErrServerClosed) {
|
if err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||||
|
shutdown()
|
||||||
return fmt.Errorf("failed to start %s listener: %w", name, err)
|
return fmt.Errorf("failed to start %s listener: %w", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -739,7 +739,7 @@ func (controller *OIDCController) resolveRequestObject(c *gin.Context) (*service
|
|||||||
func (controller *OIDCController) resolveNormalParams(c *gin.Context) (*service.AuthorizeRequest, error) {
|
func (controller *OIDCController) resolveNormalParams(c *gin.Context) (*service.AuthorizeRequest, error) {
|
||||||
var req service.AuthorizeRequest
|
var req service.AuthorizeRequest
|
||||||
|
|
||||||
var bind binding.Binding = binding.Query
|
bind := binding.Query
|
||||||
|
|
||||||
if c.Request.Method == http.MethodPost {
|
if c.Request.Method == http.MethodPost {
|
||||||
bind = binding.Form
|
bind = binding.Form
|
||||||
|
|||||||
+141
-143
@@ -81,11 +81,9 @@ func NewDefaultConfiguration(runtimeEnv RuntimeEnv) *Config {
|
|||||||
PrivateKeyPath: "./tinyauth_oidc_key",
|
PrivateKeyPath: "./tinyauth_oidc_key",
|
||||||
PublicKeyPath: "./tinyauth_oidc_key.pub",
|
PublicKeyPath: "./tinyauth_oidc_key.pub",
|
||||||
},
|
},
|
||||||
Experimental: ExperimentalConfig{
|
|
||||||
Tailscale: TailscaleConfig{
|
Tailscale: TailscaleConfig{
|
||||||
Dir: "./tailscale_state",
|
Dir: "./tailscale_state",
|
||||||
},
|
},
|
||||||
},
|
|
||||||
LabelProvider: "auto",
|
LabelProvider: "auto",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,245 +93,245 @@ func NewDefaultConfiguration(runtimeEnv RuntimeEnv) *Config {
|
|||||||
cfg.Resources.Path = "/data/resources"
|
cfg.Resources.Path = "/data/resources"
|
||||||
cfg.OIDC.PrivateKeyPath = "/data/oidc/key.pem"
|
cfg.OIDC.PrivateKeyPath = "/data/oidc/key.pem"
|
||||||
cfg.OIDC.PublicKeyPath = "/data/oidc/key.pub"
|
cfg.OIDC.PublicKeyPath = "/data/oidc/key.pub"
|
||||||
cfg.Experimental.Tailscale.Dir = "/data/tailscale"
|
cfg.Tailscale.Dir = "/data/tailscale"
|
||||||
}
|
}
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
AppURL string `description:"The base URL where the app is hosted." yaml:"appUrl,omitempty"`
|
AppURL string `description:"The base URL where the app is hosted." yaml:"appUrl"`
|
||||||
Database DatabaseConfig `description:"Database configuration." yaml:"database,omitempty"`
|
Database DatabaseConfig `description:"Database configuration." yaml:"database"`
|
||||||
Analytics AnalyticsConfig `description:"Analytics configuration." yaml:"analytics,omitempty"`
|
Analytics AnalyticsConfig `description:"Analytics configuration." yaml:"analytics"`
|
||||||
Resources ResourcesConfig `description:"Resources configuration." yaml:"resources,omitempty"`
|
Resources ResourcesConfig `description:"Resources configuration." yaml:"resources"`
|
||||||
Server ServerConfig `description:"Server configuration." yaml:"server,omitempty"`
|
Server ServerConfig `description:"Server configuration." yaml:"server"`
|
||||||
Auth AuthConfig `description:"Authentication configuration." yaml:"auth,omitempty"`
|
Auth AuthConfig `description:"Authentication configuration." yaml:"auth"`
|
||||||
Apps map[string]App `description:"Application ACLs configuration." yaml:"apps,omitempty"`
|
Apps map[string]App `description:"Application ACLs configuration." yaml:"apps"`
|
||||||
OAuth OAuthConfig `description:"OAuth configuration." yaml:"oauth,omitempty"`
|
OAuth OAuthConfig `description:"OAuth configuration." yaml:"oauth"`
|
||||||
OIDC OIDCConfig `description:"OIDC configuration." yaml:"oidc,omitempty"`
|
OIDC OIDCConfig `description:"OIDC configuration." yaml:"oidc"`
|
||||||
UI UIConfig `description:"UI customization." yaml:"ui,omitempty"`
|
UI UIConfig `description:"UI customization." yaml:"ui"`
|
||||||
LDAP LDAPConfig `description:"LDAP configuration." yaml:"ldap,omitempty"`
|
LDAP LDAPConfig `description:"LDAP configuration." yaml:"ldap"`
|
||||||
Experimental ExperimentalConfig `description:"Experimental features, use with caution." yaml:"experimental,omitempty"`
|
// Experimental ExperimentalConfig `description:"Experimental features, use with caution." yaml:"experimental"`
|
||||||
LabelProvider string `description:"Label provider to use for ACLs (auto, docker, kubernetes or none to disable). auto detects the environment." yaml:"labelProvider,omitempty"`
|
LabelProvider string `description:"Label provider to use for ACLs (auto, docker, kubernetes or none to disable). auto detects the environment." yaml:"labelProvider"`
|
||||||
Log LogConfig `description:"Logging configuration." yaml:"log,omitempty"`
|
Log LogConfig `description:"Logging configuration." yaml:"log"`
|
||||||
|
Tailscale TailscaleConfig `description:"Tailscale configuration." yaml:"tailscale"`
|
||||||
ConfigFile string `description:"Path to config file." yaml:"-"`
|
ConfigFile string `description:"Path to config file." yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DatabaseConfig struct {
|
type DatabaseConfig struct {
|
||||||
Driver string `description:"The database driver to use. Valid values: sqlite, postgres, memory." yaml:"driver,omitempty"`
|
Driver string `description:"The database driver to use. Valid values: sqlite, postgres, memory." yaml:"driver"`
|
||||||
Path string `description:"The path to the SQLite database file, or connection URL when driver is postgres." yaml:"path,omitempty"`
|
Path string `description:"The path to the SQLite database file, or connection URL when driver is postgres." yaml:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AnalyticsConfig struct {
|
type AnalyticsConfig struct {
|
||||||
Enabled bool `description:"Enable periodic version information collection." yaml:"enabled,omitempty"`
|
Enabled bool `description:"Enable periodic version information collection." yaml:"enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResourcesConfig struct {
|
type ResourcesConfig struct {
|
||||||
Enabled bool `description:"Enable the resources server." yaml:"enabled,omitempty"`
|
Enabled bool `description:"Enable the resources server." yaml:"enabled"`
|
||||||
Path string `description:"The directory where resources are stored." yaml:"path,omitempty"`
|
Path string `description:"The directory where resources are stored." yaml:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerConfig struct {
|
type ServerConfig struct {
|
||||||
Port int `description:"The port on which the server listens." yaml:"port,omitempty"`
|
Port int `description:"The port on which the server listens." yaml:"port"`
|
||||||
Address string `description:"The address on which the server listens." yaml:"address,omitempty"`
|
Address string `description:"The address on which the server listens." yaml:"address"`
|
||||||
SocketPath string `description:"The path to the Unix socket." yaml:"socketPath,omitempty"`
|
SocketPath string `description:"The path to the Unix socket." yaml:"socketPath"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthConfig struct {
|
type AuthConfig struct {
|
||||||
IP IPConfig `description:"IP whitelisting config options." yaml:"ip,omitempty"`
|
IP IPConfig `description:"IP whitelisting config options." yaml:"ip"`
|
||||||
Users []string `description:"Comma-separated list of users (username:hashed_password)." yaml:"users,omitempty"`
|
Users []string `description:"Comma-separated list of users (username:hashed_password)." yaml:"users"`
|
||||||
SubdomainsEnabled bool `description:"Enable subdomains support." yaml:"subdomainsEnabled,omitempty"`
|
SubdomainsEnabled bool `description:"Enable subdomains support." yaml:"subdomainsEnabled"`
|
||||||
UserAttributes map[string]UserAttributes `description:"Map of per-user OIDC attributes (username -> attributes)." yaml:"userAttributes,omitempty"`
|
UserAttributes map[string]UserAttributes `description:"Map of per-user OIDC attributes (username -> attributes)." yaml:"userAttributes"`
|
||||||
UsersFile string `description:"Path to the users file." yaml:"usersFile,omitempty"`
|
UsersFile string `description:"Path to the users file." yaml:"usersFile"`
|
||||||
SecureCookie bool `description:"Enable secure cookies." yaml:"secureCookie,omitempty"`
|
SecureCookie bool `description:"Enable secure cookies." yaml:"secureCookie"`
|
||||||
SessionExpiry int `description:"Session expiry time in seconds." yaml:"sessionExpiry,omitempty"`
|
SessionExpiry int `description:"Session expiry time in seconds." yaml:"sessionExpiry"`
|
||||||
SessionMaxLifetime int `description:"Maximum session lifetime in seconds." yaml:"sessionMaxLifetime,omitempty"`
|
SessionMaxLifetime int `description:"Maximum session lifetime in seconds." yaml:"sessionMaxLifetime"`
|
||||||
LoginTimeout int `description:"Login timeout in seconds." yaml:"loginTimeout,omitempty"`
|
LoginTimeout int `description:"Login timeout in seconds." yaml:"loginTimeout"`
|
||||||
LoginMaxRetries int `description:"Maximum login retries." yaml:"loginMaxRetries,omitempty"`
|
LoginMaxRetries int `description:"Maximum login retries." yaml:"loginMaxRetries"`
|
||||||
LockdownEnabled bool `description:"Enable lockdown mode after maximum login retries. Lockdown mode limit is calculated automatically." yaml:"lockdownEnabled,omitempty"`
|
LockdownEnabled bool `description:"Enable lockdown mode after maximum login retries. Lockdown mode limit is calculated automatically." yaml:"lockdownEnabled"`
|
||||||
TrustedProxies []string `description:"Comma-separated list of trusted proxy addresses." yaml:"trustedProxies,omitempty"`
|
TrustedProxies []string `description:"Comma-separated list of trusted proxy addresses." yaml:"trustedProxies"`
|
||||||
ACLs ACLsConfig `description:"ACLs configuration." yaml:"acls,omitempty"`
|
ACLs ACLsConfig `description:"ACLs configuration." yaml:"acls"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserAttributes struct {
|
type UserAttributes struct {
|
||||||
Name string `description:"Full name of the user." yaml:"name,omitempty"`
|
Name string `description:"Full name of the user." yaml:"name"`
|
||||||
GivenName string `description:"Given (first) name of the user." yaml:"givenName,omitempty"`
|
GivenName string `description:"Given (first) name of the user." yaml:"givenName"`
|
||||||
FamilyName string `description:"Family (last) name of the user." yaml:"familyName,omitempty"`
|
FamilyName string `description:"Family (last) name of the user." yaml:"familyName"`
|
||||||
MiddleName string `description:"Middle name of the user." yaml:"middleName,omitempty"`
|
MiddleName string `description:"Middle name of the user." yaml:"middleName"`
|
||||||
Nickname string `description:"Nickname of the user." yaml:"nickname,omitempty"`
|
Nickname string `description:"Nickname of the user." yaml:"nickname"`
|
||||||
Profile string `description:"URL of the user's profile page." yaml:"profile,omitempty"`
|
Profile string `description:"URL of the user's profile page." yaml:"profile"`
|
||||||
Picture string `description:"URL of the user's profile picture." yaml:"picture,omitempty"`
|
Picture string `description:"URL of the user's profile picture." yaml:"picture"`
|
||||||
Website string `description:"URL of the user's website." yaml:"website,omitempty"`
|
Website string `description:"URL of the user's website." yaml:"website"`
|
||||||
Email string `description:"Email address of the user." yaml:"email,omitempty"`
|
Email string `description:"Email address of the user." yaml:"email"`
|
||||||
Gender string `description:"Gender of the user." yaml:"gender,omitempty"`
|
Gender string `description:"Gender of the user." yaml:"gender"`
|
||||||
Birthdate string `description:"Birthdate of the user (YYYY-MM-DD)." yaml:"birthdate,omitempty"`
|
Birthdate string `description:"Birthdate of the user (YYYY-MM-DD)." yaml:"birthdate"`
|
||||||
Zoneinfo string `description:"Time zone of the user (e.g. Europe/Athens)." yaml:"zoneinfo,omitempty"`
|
Zoneinfo string `description:"Time zone of the user (e.g. Europe/Athens)." yaml:"zoneinfo"`
|
||||||
Locale string `description:"Locale of the user (e.g. en-US)." yaml:"locale,omitempty"`
|
Locale string `description:"Locale of the user (e.g. en-US)." yaml:"locale"`
|
||||||
PhoneNumber string `description:"Phone number of the user." yaml:"phoneNumber,omitempty"`
|
PhoneNumber string `description:"Phone number of the user." yaml:"phoneNumber"`
|
||||||
Address AddressClaim `description:"Address of the user." yaml:"address,omitempty"`
|
Address AddressClaim `description:"Address of the user." yaml:"address"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AddressClaim struct {
|
type AddressClaim struct {
|
||||||
Formatted string `description:"Full mailing address, formatted for display." yaml:"formatted,omitempty" json:"formatted,omitempty"`
|
Formatted string `description:"Full mailing address, formatted for display." yaml:"formatted" json:"formatted,omitempty"`
|
||||||
StreetAddress string `description:"Street address." yaml:"streetAddress,omitempty" json:"street_address,omitempty"`
|
StreetAddress string `description:"Street address." yaml:"streetAddress" json:"street_address,omitempty"`
|
||||||
Locality string `description:"City or locality." yaml:"locality,omitempty" json:"locality,omitempty"`
|
Locality string `description:"City or locality." yaml:"locality" json:"locality,omitempty"`
|
||||||
Region string `description:"State, province, or region." yaml:"region,omitempty" json:"region,omitempty"`
|
Region string `description:"State, province, or region." yaml:"region" json:"region,omitempty"`
|
||||||
PostalCode string `description:"Zip or postal code." yaml:"postalCode,omitempty" json:"postal_code,omitempty"`
|
PostalCode string `description:"Zip or postal code." yaml:"postalCode" json:"postal_code,omitempty"`
|
||||||
Country string `description:"Country." yaml:"country,omitempty" json:"country,omitempty"`
|
Country string `description:"Country." yaml:"country" json:"country,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type IPConfig struct {
|
type IPConfig struct {
|
||||||
Allow []string `description:"List of allowed IPs or CIDR ranges." yaml:"allow,omitempty"`
|
Allow []string `description:"List of allowed IPs or CIDR ranges." yaml:"allow"`
|
||||||
Block []string `description:"List of blocked IPs or CIDR ranges." yaml:"block,omitempty"`
|
Block []string `description:"List of blocked IPs or CIDR ranges." yaml:"block"`
|
||||||
Bypass []string `description:"List of IPs or CIDR ranges that bypass authentication entirely." yaml:"bypass,omitempty"`
|
Bypass []string `description:"List of IPs or CIDR ranges that bypass authentication entirely." yaml:"bypass"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OAuthConfig struct {
|
type OAuthConfig struct {
|
||||||
Whitelist []string `description:"Comma-separated list of allowed OAuth domains." yaml:"whitelist,omitempty"`
|
Whitelist []string `description:"Comma-separated list of allowed OAuth domains." yaml:"whitelist"`
|
||||||
WhitelistFile string `description:"Path to the OAuth whitelist file." yaml:"whitelistFile,omitempty"`
|
WhitelistFile string `description:"Path to the OAuth whitelist file." yaml:"whitelistFile"`
|
||||||
AutoRedirect string `description:"The OAuth provider to use for automatic redirection." yaml:"autoRedirect,omitempty"`
|
AutoRedirect string `description:"The OAuth provider to use for automatic redirection." yaml:"autoRedirect"`
|
||||||
Providers map[string]OAuthServiceConfig `description:"OAuth providers configuration." yaml:"providers,omitempty"`
|
Providers map[string]OAuthServiceConfig `description:"OAuth providers configuration." yaml:"providers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OIDCConfig struct {
|
type OIDCConfig struct {
|
||||||
PrivateKeyPath string `description:"Path to the private key file, including file name." yaml:"privateKeyPath,omitempty"`
|
PrivateKeyPath string `description:"Path to the private key file, including file name." yaml:"privateKeyPath"`
|
||||||
PublicKeyPath string `description:"Path to the public key file, including file name." yaml:"publicKeyPath,omitempty"`
|
PublicKeyPath string `description:"Path to the public key file, including file name." yaml:"publicKeyPath"`
|
||||||
Clients map[string]OIDCClientConfig `description:"OIDC clients configuration." yaml:"clients,omitempty"`
|
Clients map[string]OIDCClientConfig `description:"OIDC clients configuration." yaml:"clients"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UIConfig struct {
|
type UIConfig struct {
|
||||||
Title string `description:"The title of the UI." yaml:"title,omitempty"`
|
Title string `description:"The title of the UI." yaml:"title"`
|
||||||
ForgotPasswordMessage string `description:"Message displayed on the forgot password page." yaml:"forgotPasswordMessage,omitempty"`
|
ForgotPasswordMessage string `description:"Message displayed on the forgot password page." yaml:"forgotPasswordMessage"`
|
||||||
BackgroundImage string `description:"Path to the background image." yaml:"backgroundImage,omitempty"`
|
BackgroundImage string `description:"Path to the background image." yaml:"backgroundImage"`
|
||||||
WarningsEnabled bool `description:"Enable UI warnings." yaml:"warningsEnabled,omitempty"`
|
WarningsEnabled bool `description:"Enable UI warnings." yaml:"warningsEnabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LDAPConfig struct {
|
type LDAPConfig struct {
|
||||||
Address string `description:"LDAP server address." yaml:"address,omitempty"`
|
Address string `description:"LDAP server address." yaml:"address"`
|
||||||
BindDN string `description:"Bind DN for LDAP authentication." yaml:"bindDn,omitempty"`
|
BindDN string `description:"Bind DN for LDAP authentication." yaml:"bindDn"`
|
||||||
BindPassword string `description:"Bind password for LDAP authentication." yaml:"bindPassword,omitempty"`
|
BindPassword string `description:"Bind password for LDAP authentication." yaml:"bindPassword"`
|
||||||
BindPasswordFile string `description:"Path to the Bind password." yaml:"bindPasswordFile,omitempty"`
|
BindPasswordFile string `description:"Path to the Bind password." yaml:"bindPasswordFile"`
|
||||||
BaseDN string `description:"Base DN for LDAP searches." yaml:"baseDn,omitempty"`
|
BaseDN string `description:"Base DN for LDAP searches." yaml:"baseDn"`
|
||||||
Insecure bool `description:"Allow insecure LDAP connections." yaml:"insecure,omitempty"`
|
Insecure bool `description:"Allow insecure LDAP connections." yaml:"insecure"`
|
||||||
SearchFilter string `description:"LDAP search filter." yaml:"searchFilter,omitempty"`
|
SearchFilter string `description:"LDAP search filter." yaml:"searchFilter"`
|
||||||
AuthCert string `description:"Certificate for mTLS authentication." yaml:"authCert,omitempty"`
|
AuthCert string `description:"Certificate for mTLS authentication." yaml:"authCert"`
|
||||||
AuthKey string `description:"Certificate key for mTLS authentication." yaml:"authKey,omitempty"`
|
AuthKey string `description:"Certificate key for mTLS authentication." yaml:"authKey"`
|
||||||
GroupCacheTTL int `description:"Cache duration for LDAP group membership in seconds." yaml:"groupCacheTTL,omitempty"`
|
GroupCacheTTL int `description:"Cache duration for LDAP group membership in seconds." yaml:"groupCacheTTL"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogConfig struct {
|
type LogConfig struct {
|
||||||
Level string `description:"Log level (trace, debug, info, warn, error)." yaml:"level,omitempty"`
|
Level string `description:"Log level (trace, debug, info, warn, error)." yaml:"level"`
|
||||||
Json bool `description:"Enable JSON formatted logs." yaml:"json,omitempty"`
|
Json bool `description:"Enable JSON formatted logs." yaml:"json"`
|
||||||
Streams LogStreams `description:"Configuration for specific log streams." yaml:"streams,omitempty"`
|
Streams LogStreams `description:"Configuration for specific log streams." yaml:"streams"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogStreams struct {
|
type LogStreams struct {
|
||||||
HTTP LogStreamConfig `description:"HTTP request logging." yaml:"http,omitempty"`
|
HTTP LogStreamConfig `description:"HTTP request logging." yaml:"http"`
|
||||||
App LogStreamConfig `description:"Application logging." yaml:"app,omitempty"`
|
App LogStreamConfig `description:"Application logging." yaml:"app"`
|
||||||
Audit LogStreamConfig `description:"Audit logging." yaml:"audit,omitempty"`
|
Audit LogStreamConfig `description:"Audit logging." yaml:"audit"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogStreamConfig struct {
|
type LogStreamConfig struct {
|
||||||
Enabled bool `description:"Enable this log stream." yaml:"enabled,omitempty"`
|
Enabled bool `description:"Enable this log stream." yaml:"enabled"`
|
||||||
Level string `description:"Log level for this stream. Use global if empty." yaml:"level,omitempty"`
|
Level string `description:"Log level for this stream. Use global if empty." yaml:"level"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExperimentalConfig struct {
|
// no experimental features
|
||||||
Tailscale TailscaleConfig `description:"Tailscale configuration." yaml:"tailscale"`
|
type ExperimentalConfig struct{}
|
||||||
}
|
|
||||||
|
|
||||||
type TailscaleConfig struct {
|
type TailscaleConfig struct {
|
||||||
Enabled bool `description:"Enable Tailscale integration." yaml:"enabled,omitempty"`
|
Enabled bool `description:"Enable Tailscale integration." yaml:"enabled"`
|
||||||
Dir string `description:"Tailscale state directory." yaml:"dir,omitempty"`
|
Dir string `description:"Tailscale state directory." yaml:"dir"`
|
||||||
Hostname string `description:"Tailscale hostname." yaml:"hostname,omitempty"`
|
Hostname string `description:"Tailscale hostname." yaml:"hostname"`
|
||||||
AuthKey string `description:"Tailscale auth key." yaml:"authKey,omitempty"`
|
AuthKey string `description:"Tailscale auth key." yaml:"authKey"`
|
||||||
Ephemeral bool `description:"Use ephemeral Tailscale node." yaml:"ephemeral,omitempty"`
|
Ephemeral bool `description:"Use ephemeral Tailscale node." yaml:"ephemeral"`
|
||||||
Funnel bool `description:"Enable Tailscale Funnel." yaml:"funnel,omitempty"`
|
Funnel bool `description:"Enable Tailscale Funnel." yaml:"funnel"`
|
||||||
Listen bool `description:"Listen on the Tailscale address instead of standard address." yaml:"listen,omitempty"`
|
Listen bool `description:"Listen on the Tailscale address instead of standard address." yaml:"listen"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// OAuth/OIDC config
|
// OAuth/OIDC config
|
||||||
|
|
||||||
type OAuthServiceConfig struct {
|
type OAuthServiceConfig struct {
|
||||||
ClientID string `description:"OAuth client ID." yaml:"clientId,omitempty"`
|
ClientID string `description:"OAuth client ID." yaml:"clientId"`
|
||||||
ClientSecret string `description:"OAuth client secret." yaml:"clientSecret,omitempty"`
|
ClientSecret string `description:"OAuth client secret." yaml:"clientSecret"`
|
||||||
ClientSecretFile string `description:"Path to the file containing the OAuth client secret." yaml:"clientSecretFile,omitempty"`
|
ClientSecretFile string `description:"Path to the file containing the OAuth client secret." yaml:"clientSecretFile"`
|
||||||
Whitelist []string `description:"Comma-separated list of allowed OAuth domains for this provider." yaml:"whitelist,omitempty"`
|
Whitelist []string `description:"Comma-separated list of allowed OAuth domains for this provider." yaml:"whitelist"`
|
||||||
WhitelistFile string `description:"Path to the OAuth whitelist file for this provider." yaml:"whitelistFile,omitempty"`
|
WhitelistFile string `description:"Path to the OAuth whitelist file for this provider." yaml:"whitelistFile"`
|
||||||
Scopes []string `description:"OAuth scopes." yaml:"scopes,omitempty"`
|
Scopes []string `description:"OAuth scopes." yaml:"scopes"`
|
||||||
RedirectURL string `description:"OAuth redirect URL." yaml:"redirectUrl,omitempty"`
|
RedirectURL string `description:"OAuth redirect URL." yaml:"redirectUrl"`
|
||||||
AuthURL string `description:"OAuth authorization URL." yaml:"authUrl,omitempty"`
|
AuthURL string `description:"OAuth authorization URL." yaml:"authUrl"`
|
||||||
TokenURL string `description:"OAuth token URL." yaml:"tokenUrl,omitempty"`
|
TokenURL string `description:"OAuth token URL." yaml:"tokenUrl"`
|
||||||
UserinfoURL string `description:"OAuth userinfo URL." yaml:"userinfoUrl,omitempty"`
|
UserinfoURL string `description:"OAuth userinfo URL." yaml:"userinfoUrl"`
|
||||||
Insecure bool `description:"Allow insecure OAuth connections." yaml:"insecure,omitempty"`
|
Insecure bool `description:"Allow insecure OAuth connections." yaml:"insecure"`
|
||||||
Name string `description:"Provider name in UI." yaml:"name,omitempty"`
|
Name string `description:"Provider name in UI." yaml:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OIDCClientConfig struct {
|
type OIDCClientConfig struct {
|
||||||
ID string `description:"OIDC client ID." yaml:"-"`
|
ID string `description:"OIDC client ID." yaml:"-"`
|
||||||
ClientID string `description:"OIDC client ID." yaml:"clientId,omitempty"`
|
ClientID string `description:"OIDC client ID." yaml:"clientId"`
|
||||||
ClientSecret string `description:"OIDC client secret." yaml:"clientSecret,omitempty"`
|
ClientSecret string `description:"OIDC client secret." yaml:"clientSecret"`
|
||||||
ClientSecretFile string `description:"Path to the file containing the OIDC client secret." yaml:"clientSecretFile,omitempty"`
|
ClientSecretFile string `description:"Path to the file containing the OIDC client secret." yaml:"clientSecretFile"`
|
||||||
TrustedRedirectURIs []string `description:"List of trusted redirect URIs." yaml:"trustedRedirectUris,omitempty"`
|
TrustedRedirectURIs []string `description:"List of trusted redirect URIs." yaml:"trustedRedirectUris"`
|
||||||
Name string `description:"Client name in UI." yaml:"name,omitempty"`
|
Name string `description:"Client name in UI." yaml:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ACLsConfig struct {
|
type ACLsConfig struct {
|
||||||
Policy string `description:"ACL policy for allow-by-default or deny-by-default, available options are allow and deny, default is allow." yaml:"policy,omitempty"`
|
Policy string `description:"ACL policy for allow-by-default or deny-by-default, available options are allow and deny, default is allow." yaml:"policy"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACLs
|
// ACLs
|
||||||
|
|
||||||
type Apps struct {
|
type Apps struct {
|
||||||
Apps map[string]App `description:"App ACLs configuration." yaml:"apps,omitempty"`
|
Apps map[string]App `description:"App ACLs configuration." yaml:"apps"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
Config AppConfig `description:"App configuration." yaml:"config,omitempty"`
|
Config AppConfig `description:"App configuration." yaml:"config"`
|
||||||
Users AppUsers `description:"User access configuration." yaml:"users,omitempty"`
|
Users AppUsers `description:"User access configuration." yaml:"users"`
|
||||||
OAuth AppOAuth `description:"OAuth access configuration." yaml:"oauth,omitempty"`
|
OAuth AppOAuth `description:"OAuth access configuration." yaml:"oauth"`
|
||||||
IP AppIP `description:"IP access configuration." yaml:"ip,omitempty"`
|
IP AppIP `description:"IP access configuration." yaml:"ip"`
|
||||||
Response AppResponse `description:"Response customization." yaml:"response,omitempty"`
|
Response AppResponse `description:"Response customization." yaml:"response"`
|
||||||
Path AppPath `description:"Path access configuration." yaml:"path,omitempty"`
|
Path AppPath `description:"Path access configuration." yaml:"path"`
|
||||||
LDAP AppLDAP `description:"LDAP access configuration." yaml:"ldap,omitempty"`
|
LDAP AppLDAP `description:"LDAP access configuration." yaml:"ldap"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppConfig struct {
|
type AppConfig struct {
|
||||||
Domain string `description:"The domain of the app." yaml:"domain,omitempty"`
|
Domain string `description:"The domain of the app." yaml:"domain"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppUsers struct {
|
type AppUsers struct {
|
||||||
Allow string `description:"Comma-separated list of allowed users." yaml:"allow,omitempty"`
|
Allow string `description:"Comma-separated list of allowed users." yaml:"allow"`
|
||||||
Block string `description:"Comma-separated list of blocked users." yaml:"block,omitempty"`
|
Block string `description:"Comma-separated list of blocked users." yaml:"block"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppOAuth struct {
|
type AppOAuth struct {
|
||||||
Whitelist string `description:"Comma-separated list of allowed OAuth groups." yaml:"whitelist,omitempty"`
|
Whitelist string `description:"Comma-separated list of allowed OAuth groups." yaml:"whitelist"`
|
||||||
Groups string `description:"Comma-separated list of required OAuth groups." yaml:"groups,omitempty"`
|
Groups string `description:"Comma-separated list of required OAuth groups." yaml:"groups"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppLDAP struct {
|
type AppLDAP struct {
|
||||||
Groups string `description:"Comma-separated list of required LDAP groups." yaml:"groups,omitempty"`
|
Groups string `description:"Comma-separated list of required LDAP groups." yaml:"groups"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppIP struct {
|
type AppIP struct {
|
||||||
Allow []string `description:"List of allowed IPs or CIDR ranges." yaml:"allow,omitempty"`
|
Allow []string `description:"List of allowed IPs or CIDR ranges." yaml:"allow"`
|
||||||
Block []string `description:"List of blocked IPs or CIDR ranges." yaml:"block,omitempty"`
|
Block []string `description:"List of blocked IPs or CIDR ranges." yaml:"block"`
|
||||||
Bypass []string `description:"List of IPs or CIDR ranges that bypass authentication." yaml:"bypass,omitempty"`
|
Bypass []string `description:"List of IPs or CIDR ranges that bypass authentication." yaml:"bypass"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppResponse struct {
|
type AppResponse struct {
|
||||||
Headers []string `description:"Custom headers to add to the response." yaml:"headers,omitempty"`
|
Headers []string `description:"Custom headers to add to the response." yaml:"headers"`
|
||||||
BasicAuth AppBasicAuth `description:"Basic authentication for the app." yaml:"basicAuth,omitempty"`
|
BasicAuth AppBasicAuth `description:"Basic authentication for the app." yaml:"basicAuth"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppBasicAuth struct {
|
type AppBasicAuth struct {
|
||||||
Username string `description:"Basic auth username." yaml:"username,omitempty"`
|
Username string `description:"Basic auth username." yaml:"username"`
|
||||||
Password string `description:"Basic auth password." yaml:"password,omitempty"`
|
Password string `description:"Basic auth password." yaml:"password"`
|
||||||
PasswordFile string `description:"Path to the file containing the basic auth password." yaml:"passwordFile,omitempty"`
|
PasswordFile string `description:"Path to the file containing the basic auth password." yaml:"passwordFile"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppPath struct {
|
type AppPath struct {
|
||||||
Allow string `description:"Comma-separated list of allowed paths." yaml:"allow,omitempty"`
|
Allow string `description:"Comma-separated list of allowed paths." yaml:"allow"`
|
||||||
Block string `description:"Comma-separated list of blocked paths." yaml:"block,omitempty"`
|
Block string `description:"Comma-separated list of blocked paths." yaml:"block"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
package postgres
|
package postgres
|
||||||
|
|
||||||
//go:generate go run github.com/tinyauthapp/tinyauth/gen/sqlc_wrapper -pkg github.com/tinyauthapp/tinyauth/internal/repository/postgres
|
//go:generate go run github.com/tinyauthapp/tinyauth/gen/sqlc-wrapper -pkg github.com/tinyauthapp/tinyauth/internal/repository/postgres
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
package sqlite
|
package sqlite
|
||||||
|
|
||||||
//go:generate go run github.com/tinyauthapp/tinyauth/gen/sqlc_wrapper -pkg github.com/tinyauthapp/tinyauth/internal/repository/sqlite
|
//go:generate go run github.com/tinyauthapp/tinyauth/gen/sqlc-wrapper -pkg github.com/tinyauthapp/tinyauth/internal/repository/sqlite
|
||||||
|
|||||||
@@ -45,17 +45,17 @@ type TailscaleServiceInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewTailscaleService(i TailscaleServiceInput) (*TailscaleService, error) {
|
func NewTailscaleService(i TailscaleServiceInput) (*TailscaleService, error) {
|
||||||
if !i.Config.Experimental.Tailscale.Enabled {
|
if !i.Config.Tailscale.Enabled {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
srv := new(tsnet.Server)
|
srv := new(tsnet.Server)
|
||||||
|
|
||||||
// node options
|
// node options
|
||||||
srv.Dir = i.Config.Experimental.Tailscale.Dir
|
srv.Dir = i.Config.Tailscale.Dir
|
||||||
srv.Hostname = i.Config.Experimental.Tailscale.Hostname
|
srv.Hostname = i.Config.Tailscale.Hostname
|
||||||
srv.AuthKey = i.Config.Experimental.Tailscale.AuthKey
|
srv.AuthKey = i.Config.Tailscale.AuthKey
|
||||||
srv.Ephemeral = i.Config.Experimental.Tailscale.Ephemeral
|
srv.Ephemeral = i.Config.Tailscale.Ephemeral
|
||||||
|
|
||||||
// redirect logs to zerolog
|
// redirect logs to zerolog
|
||||||
srv.Logf = i.Log.App.Printf
|
srv.Logf = i.Log.App.Printf
|
||||||
@@ -94,7 +94,7 @@ func NewTailscaleService(i TailscaleServiceInput) (*TailscaleService, error) {
|
|||||||
|
|
||||||
i.Ding.Go(service.watchAndClose, ding.RingMajor)
|
i.Ding.Go(service.watchAndClose, ding.RingMajor)
|
||||||
|
|
||||||
if i.Config.Experimental.Tailscale.Funnel && !i.Config.Experimental.Tailscale.Listen {
|
if i.Config.Tailscale.Funnel && !i.Config.Tailscale.Listen {
|
||||||
service.log.App.Warn().Msg("Tailscale Funnel is enabled but listen is disabled. Funnel will not work without listen enabled.")
|
service.log.App.Warn().Msg("Tailscale Funnel is enabled but listen is disabled. Funnel will not work without listen enabled.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ func (ts *TailscaleService) CreateListener() (net.Listener, error) {
|
|||||||
return *ts.ln, nil
|
return *ts.ln, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if ts.config.Experimental.Tailscale.Funnel {
|
if ts.config.Tailscale.Funnel {
|
||||||
ln, err := ts.srv.ListenFunnel("tcp", ":443")
|
ln, err := ts.srv.ListenFunnel("tcp", ":443")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
Reference in New Issue
Block a user