From 513a88826d33dd9126ee6b58fea305223bcbe94c Mon Sep 17 00:00:00 2001 From: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> Date: Mon, 20 Oct 2025 12:59:37 -0500 Subject: [PATCH 01/11] Update Docker image name for GitHub registry --- .github/workflows/docker-image.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index bab6cd4f..d2e1e90c 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -84,13 +84,12 @@ jobs: fi echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV - # Determine registry and image name if [ "${{ github.event.inputs.registry }}" == "dockerhub" ]; then echo "REGISTRY=docker.io" >> $GITHUB_ENV echo "IMAGE_NAME=bugattiguy527/termix" >> $GITHUB_ENV else echo "REGISTRY=ghcr.io" >> $GITHUB_ENV - echo "IMAGE_NAME=$REPO_OWNER/termix" >> $GITHUB_ENV + echo "IMAGE_NAME=LukeGus/termix" >> $GITHUB_ENV fi - name: Build and Push Multi-Arch Docker Image -- 2.49.1 From 2450ae732ecfdef2feb73e3ec9f0d5797e8f1cc5 Mon Sep 17 00:00:00 2001 From: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> Date: Mon, 20 Oct 2025 13:04:59 -0500 Subject: [PATCH 02/11] Fix image name casing in Docker workflow --- .github/workflows/docker-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index d2e1e90c..8b58b145 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -89,7 +89,7 @@ jobs: echo "IMAGE_NAME=bugattiguy527/termix" >> $GITHUB_ENV else echo "REGISTRY=ghcr.io" >> $GITHUB_ENV - echo "IMAGE_NAME=LukeGus/termix" >> $GITHUB_ENV + echo "IMAGE_NAME=lukegus/termix" >> $GITHUB_ENV fi - name: Build and Push Multi-Arch Docker Image -- 2.49.1 From 8c867d3b16f2ac827a9de911f121075a1de72925 Mon Sep 17 00:00:00 2001 From: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> Date: Mon, 20 Oct 2025 15:13:40 -0500 Subject: [PATCH 03/11] Remove untagged image cleanup step from workflow Removed the step to delete untagged image versions from the workflow. --- .github/workflows/docker-image.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 8b58b145..5bfc6c70 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -113,15 +113,6 @@ jobs: rm -rf /tmp/.buildx-cache mv /tmp/.buildx-cache-new /tmp/.buildx-cache - - name: Delete all untagged image versions - if: success() && github.event.inputs.registry != 'dockerhub' - uses: quartx-analytics/ghcr-cleaner@v1 - with: - owner-type: user - token: ${{ secrets.GHCR_TOKEN }} - repository-owner: ${{ github.repository_owner }} - delete-untagged: true - - name: Cleanup Docker Images Locally if: always() run: | -- 2.49.1 From 9dd79929e88df81ce4af392ce84fa38d235d463c Mon Sep 17 00:00:00 2001 From: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> Date: Mon, 20 Oct 2025 15:22:41 -0500 Subject: [PATCH 04/11] Change Docker login to use GHCR credentials Updated Docker login credentials for GitHub Container Registry. --- .github/workflows/docker-image.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 5bfc6c70..7a2af48e 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -58,8 +58,8 @@ jobs: uses: docker/login-action@v3 with: registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + username: lukegus + password: ${{ secrets.GHCR_TOKEN }} - name: Login to Docker Hub if: github.event.inputs.registry == 'dockerhub' -- 2.49.1 From 300e0a263f89c9590e957d724d63f04d86b56399 Mon Sep 17 00:00:00 2001 From: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> Date: Mon, 20 Oct 2025 15:35:52 -0500 Subject: [PATCH 05/11] Remove cache moving step from Docker workflow Removed the step to move the build cache in the Docker workflow. --- .github/workflows/docker-image.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 7a2af48e..aa42b2e6 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -108,11 +108,6 @@ jobs: BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 outputs: type=registry,compression=zstd,compression-level=19 - - name: Move cache - run: | - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache - - name: Cleanup Docker Images Locally if: always() run: | -- 2.49.1 From ad1864f062e57651b04bd332827cad4d706a0071 Mon Sep 17 00:00:00 2001 From: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:22:11 -0500 Subject: [PATCH 06/11] Refactor Docker image workflow for versioning and builds --- .github/workflows/docker-image.yml | 113 ++++++++++------------------- 1 file changed, 39 insertions(+), 74 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index aa42b2e6..a616abc4 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -3,103 +3,50 @@ name: Build and Push Docker Image on: workflow_dispatch: inputs: - tag_name: - description: "Custom tag name for the Docker image" - required: false - default: "" - registry: - description: "Docker registry to push to" + version: + description: "Version to build, e.g. 1.8.0" required: true - default: "ghcr" - type: choice - options: - - "ghcr" - - "dockerhub" + production: + description: "Set true for prod build, false for dev build" + required: true + default: false jobs: build: runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - - name: Checkout repository - uses: actions/checkout@v5 + - uses: actions/checkout@v5 with: fetch-depth: 1 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-qemu-action@v3 with: - platforms: arm64 + platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 - - name: Setup Blacksmith Builder - uses: useblacksmith/setup-docker-builder@v1 + - uses: useblacksmith/setup-docker-builder@v1 - - name: Cache npm dependencies - uses: actions/cache@v4 - with: - path: | - ~/.npm - node_modules - */*/node_modules - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node- - - - name: Cache Docker layers - uses: actions/cache@v4 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.ref_name }}-${{ hashFiles('docker/Dockerfile') }} - restore-keys: | - ${{ runner.os }}-buildx-${{ github.ref_name }}- - ${{ runner.os }}-buildx- - - - name: Login to GitHub Container Registry - if: github.event.inputs.registry != 'dockerhub' - uses: docker/login-action@v3 + - uses: docker/login-action@v3 with: registry: ghcr.io username: lukegus password: ${{ secrets.GHCR_TOKEN }} - - name: Login to Docker Hub - if: github.event.inputs.registry == 'dockerhub' - uses: docker/login-action@v3 + - uses: docker/login-action@v3 + if: ${{ github.event.inputs.production == 'true' }} with: username: bugattiguy527 password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Determine Docker image tag - run: | - REPO_OWNER=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]') - echo "REPO_OWNER=$REPO_OWNER" >> $GITHUB_ENV - - if [ "${{ github.event.inputs.tag_name }}" != "" ]; then - IMAGE_TAG="${{ github.event.inputs.tag_name }}" - elif [ "${{ github.ref }}" == "refs/heads/main" ]; then - IMAGE_TAG="latest" - elif [ "${{ github.ref }}" == "refs/heads/development" ]; then - IMAGE_TAG="development-latest" - else - IMAGE_TAG="${{ github.ref_name }}" - fi - echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV - - if [ "${{ github.event.inputs.registry }}" == "dockerhub" ]; then - echo "REGISTRY=docker.io" >> $GITHUB_ENV - echo "IMAGE_NAME=bugattiguy527/termix" >> $GITHUB_ENV - else - echo "REGISTRY=ghcr.io" >> $GITHUB_ENV - echo "IMAGE_NAME=lukegus/termix" >> $GITHUB_ENV - fi - - - name: Build and Push Multi-Arch Docker Image + - name: Build and Push to GHCR uses: useblacksmith/build-push-action@v2 with: context: . file: ./docker/Dockerfile push: true - platforms: linux/amd64,linux/arm64 - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} + platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 + tags: | + ${{ github.event.inputs.production == 'true' && format('ghcr.io/lukegus/termix:release-{0}', github.event.inputs.version) || format('ghcr.io/lukegus/termix:dev-{0}', github.event.inputs.version) }} + ${{ github.event.inputs.production == 'true' && 'ghcr.io/lukegus/termix:latest' || '' }} labels: | org.opencontainers.image.source=https://github.com/${{ github.repository }} org.opencontainers.image.revision=${{ github.sha }} @@ -108,8 +55,26 @@ jobs: BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 outputs: type=registry,compression=zstd,compression-level=19 - - name: Cleanup Docker Images Locally - if: always() - run: | + - name: Build and Push to Docker Hub + if: ${{ github.event.inputs.production == 'true' }} + uses: useblacksmith/build-push-action@v2 + with: + context: . + file: ./docker/Dockerfile + push: true + platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 + tags: | + docker.io/bugattiguy527/termix:release-${{ github.event.inputs.version }} + docker.io/bugattiguy527/termix:latest + labels: | + org.opencontainers.image.source=https://github.com/${{ github.repository }} + org.opencontainers.image.revision=${{ github.sha }} + build-args: | + BUILDKIT_INLINE_CACHE=1 + BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 + outputs: type=registry,compression=zstd,compression-level=19 + + - run: | docker image prune -af docker system prune -af --volumes + if: always() -- 2.49.1 From 40ac75de813abcf31e04390d72c762a1597826d4 Mon Sep 17 00:00:00 2001 From: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> Date: Mon, 20 Oct 2025 17:14:19 -0500 Subject: [PATCH 07/11] Update docker-image.yml --- .github/workflows/docker-image.yml | 86 +++++++++++++++++------------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index a616abc4..80ab5da6 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -4,77 +4,91 @@ on: workflow_dispatch: inputs: version: - description: "Version to build, e.g. 1.8.0" + description: "Version to build (e.g., 1.8.0)" required: true production: - description: "Set true for prod build, false for dev build" + description: "Is this a production build?" required: true default: false + type: boolean jobs: build: - runs-on: blacksmith-4vcpu-ubuntu-2404 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - name: Checkout repository + uses: actions/checkout@v5 with: fetch-depth: 1 - - uses: docker/setup-qemu-action@v3 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 with: - platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 + platforms: linux/amd64,linux/arm64,linux/arm/v7 - - uses: useblacksmith/setup-docker-builder@v1 + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 - - uses: docker/login-action@v3 + - name: Determine tags + id: tags + run: | + VERSION=${{ github.event.inputs.version }} + PROD=${{ github.event.inputs.production }} + + TAGS=() + ALL_TAGS=() + + if [ "$PROD" = "true" ]; then + # Production build → push release + latest to both GHCR and Docker Hub + TAGS+=("release-$VERSION" "latest") + for tag in "${TAGS[@]}"; do + ALL_TAGS+=("ghcr.io/lukegus/termix:$tag") + ALL_TAGS+=("docker.io/bugattiguy527/termix:$tag") + done + else + # Dev build → push only dev-x.x.x to GHCR + TAGS+=("dev-$VERSION") + for tag in "${TAGS[@]}"; do + ALL_TAGS+=("ghcr.io/lukegus/termix:$tag") + done + fi + + echo "ALL_TAGS=${ALL_TAGS[*]}" >> $GITHUB_ENV + echo "All tags to build:" + printf '%s\n' "${ALL_TAGS[@]}" + + - name: Login to GHCR + uses: docker/login-action@v3 with: registry: ghcr.io username: lukegus password: ${{ secrets.GHCR_TOKEN }} - - uses: docker/login-action@v3 + - name: Login to Docker Hub (prod only) if: ${{ github.event.inputs.production == 'true' }} + uses: docker/login-action@v3 with: username: bugattiguy527 password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Build and Push to GHCR - uses: useblacksmith/build-push-action@v2 + - name: Build and push multi-arch image + uses: docker/build-push-action@v5 with: context: . file: ./docker/Dockerfile push: true - platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 - tags: | - ${{ github.event.inputs.production == 'true' && format('ghcr.io/lukegus/termix:release-{0}', github.event.inputs.version) || format('ghcr.io/lukegus/termix:dev-{0}', github.event.inputs.version) }} - ${{ github.event.inputs.production == 'true' && 'ghcr.io/lukegus/termix:latest' || '' }} - labels: | - org.opencontainers.image.source=https://github.com/${{ github.repository }} - org.opencontainers.image.revision=${{ github.sha }} + platforms: linux/amd64,linux/arm64,linux/arm/v7 + tags: ${{ env.ALL_TAGS }} build-args: | BUILDKIT_INLINE_CACHE=1 BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 - outputs: type=registry,compression=zstd,compression-level=19 - - - name: Build and Push to Docker Hub - if: ${{ github.event.inputs.production == 'true' }} - uses: useblacksmith/build-push-action@v2 - with: - context: . - file: ./docker/Dockerfile - push: true - platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 - tags: | - docker.io/bugattiguy527/termix:release-${{ github.event.inputs.version }} - docker.io/bugattiguy527/termix:latest labels: | org.opencontainers.image.source=https://github.com/${{ github.repository }} org.opencontainers.image.revision=${{ github.sha }} - build-args: | - BUILDKIT_INLINE_CACHE=1 - BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 outputs: type=registry,compression=zstd,compression-level=19 - - run: | + - name: Cleanup Docker + if: always() + run: | docker image prune -af docker system prune -af --volumes - if: always() -- 2.49.1 From 773e22fa3d1f8de525ca2652c717259f57ffdb3a Mon Sep 17 00:00:00 2001 From: Nikola Novoselec Date: Tue, 21 Oct 2025 17:02:29 +0200 Subject: [PATCH 08/11] Allow OIDC users to import database without password --- src/backend/database/database.ts | 46 +++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/backend/database/database.ts b/src/backend/database/database.ts index 48f7aaa0..648fc029 100644 --- a/src/backend/database/database.ts +++ b/src/backend/database/database.ts @@ -918,17 +918,38 @@ app.post( const userId = (req as any).userId; const { password } = req.body; + const mainDb = getDb(); - if (!password) { - return res.status(400).json({ - error: "Password required for import", - code: "PASSWORD_REQUIRED", - }); + const userRecords = await mainDb + .select() + .from(users) + .where(eq(users.id, userId)); + + if (!userRecords || userRecords.length === 0) { + return res.status(404).json({ error: "User not found" }); } - const unlocked = await authManager.authenticateUser(userId, password); - if (!unlocked) { - return res.status(401).json({ error: "Invalid password" }); + const isOidcUser = !!userRecords[0].is_oidc; + + if (!isOidcUser) { + if (!password) { + return res.status(400).json({ + error: "Password required for import", + code: "PASSWORD_REQUIRED", + }); + } + + const unlocked = await authManager.authenticateUser(userId, password); + if (!unlocked) { + return res.status(401).json({ error: "Invalid password" }); + } + } else if (!DataCrypto.getUserDataKey(userId)) { + const oidcUnlocked = await authManager.authenticateOIDCUser(userId); + if (!oidcUnlocked) { + return res.status(403).json({ + error: "Failed to unlock user data with SSO credentials", + }); + } } apiLogger.info("Importing SQLite data", { @@ -939,7 +960,13 @@ app.post( mimetype: req.file.mimetype, }); - const userDataKey = DataCrypto.getUserDataKey(userId); + let userDataKey = DataCrypto.getUserDataKey(userId); + if (!userDataKey && isOidcUser) { + const oidcUnlocked = await authManager.authenticateOIDCUser(userId); + if (oidcUnlocked) { + userDataKey = DataCrypto.getUserDataKey(userId); + } + } if (!userDataKey) { throw new Error("User data not unlocked"); } @@ -993,7 +1020,6 @@ app.post( }; try { - const mainDb = getDb(); try { const importedHosts = importDb -- 2.49.1 From 153000d3ff7b7569d8b9fe693011922be369a48e Mon Sep 17 00:00:00 2001 From: Nikola Novoselec Date: Tue, 21 Oct 2025 17:31:51 +0200 Subject: [PATCH 09/11] Skip import password prompt for OIDC users --- src/ui/Desktop/Admin/AdminSettings.tsx | 40 +++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/ui/Desktop/Admin/AdminSettings.tsx b/src/ui/Desktop/Admin/AdminSettings.tsx index e176e234..c1e4b0ad 100644 --- a/src/ui/Desktop/Admin/AdminSettings.tsx +++ b/src/ui/Desktop/Admin/AdminSettings.tsx @@ -44,6 +44,7 @@ import { makeUserAdmin, removeAdminStatus, deleteUser, + getUserInfo, getCookie, isElectron, } from "@/ui/main-axios.ts"; @@ -92,6 +93,12 @@ export function AdminSettings({ ); const [securityInitialized, setSecurityInitialized] = React.useState(true); + const [currentUser, setCurrentUser] = React.useState<{ + id: string; + username: string; + is_admin: boolean; + is_oidc: boolean; + } | null>(null); const [exportLoading, setExportLoading] = React.useState(false); const [importLoading, setImportLoading] = React.useState(false); @@ -100,6 +107,11 @@ export function AdminSettings({ const [showPasswordInput, setShowPasswordInput] = React.useState(false); const [importPassword, setImportPassword] = React.useState(""); + const requiresImportPassword = React.useMemo( + () => !currentUser?.is_oidc, + [currentUser?.is_oidc], + ); + React.useEffect(() => { if (isElectron()) { const serverUrl = (window as any).configuredServerUrl; @@ -117,6 +129,22 @@ export function AdminSettings({ toast.error(t("admin.failedToFetchOidcConfig")); } }); + getUserInfo() + .then((info) => { + if (info) { + setCurrentUser({ + id: info.userId, + username: info.username, + is_admin: info.is_admin, + is_oidc: info.is_oidc, + }); + } + }) + .catch((err) => { + if (!err?.message?.includes("No server configured")) { + console.warn("Failed to fetch current user info", err); + } + }); fetchUsers(); }, []); @@ -334,7 +362,7 @@ export function AdminSettings({ return; } - if (!importPassword.trim()) { + if (requiresImportPassword && !importPassword.trim()) { toast.error(t("admin.passwordRequired")); return; } @@ -357,7 +385,9 @@ export function AdminSettings({ const formData = new FormData(); formData.append("file", importFile); - formData.append("password", importPassword); + if (requiresImportPassword) { + formData.append("password", importPassword); + } const response = await fetch(apiUrl, { method: "POST", @@ -966,7 +996,7 @@ export function AdminSettings({ - {importFile && ( + {importFile && requiresImportPassword && (
-- 2.49.1 From 6f1b92b07b6e3426d78011e919c4d5d010ffcffd Mon Sep 17 00:00:00 2001 From: Nikola Novoselec Date: Tue, 21 Oct 2025 17:39:31 +0200 Subject: [PATCH 10/11] docs: clarify OIDC import unlocking flow --- src/backend/database/database.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/backend/database/database.ts b/src/backend/database/database.ts index 648fc029..60549725 100644 --- a/src/backend/database/database.ts +++ b/src/backend/database/database.ts @@ -932,6 +932,7 @@ app.post( const isOidcUser = !!userRecords[0].is_oidc; if (!isOidcUser) { + // Local accounts still prove knowledge of the password so their DEK can be derived again. if (!password) { return res.status(400).json({ error: "Password required for import", @@ -944,6 +945,7 @@ app.post( return res.status(401).json({ error: "Invalid password" }); } } else if (!DataCrypto.getUserDataKey(userId)) { + // OIDC users skip the password prompt; make sure their DEK is unlocked via the OIDC session. const oidcUnlocked = await authManager.authenticateOIDCUser(userId); if (!oidcUnlocked) { return res.status(403).json({ @@ -962,6 +964,7 @@ app.post( let userDataKey = DataCrypto.getUserDataKey(userId); if (!userDataKey && isOidcUser) { + // authenticateOIDCUser lazily provisions the session key; retry the fetch when it succeeds. const oidcUnlocked = await authManager.authenticateOIDCUser(userId); if (oidcUnlocked) { userDataKey = DataCrypto.getUserDataKey(userId); -- 2.49.1 From 798be582713dc71c13ca0c1677df5286639d5995 Mon Sep 17 00:00:00 2001 From: Nikola Novoselec Date: Tue, 21 Oct 2025 17:39:41 +0200 Subject: [PATCH 11/11] docs: explain admin import password logic --- src/ui/Desktop/Admin/AdminSettings.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ui/Desktop/Admin/AdminSettings.tsx b/src/ui/Desktop/Admin/AdminSettings.tsx index c1e4b0ad..b04a0c20 100644 --- a/src/ui/Desktop/Admin/AdminSettings.tsx +++ b/src/ui/Desktop/Admin/AdminSettings.tsx @@ -107,6 +107,7 @@ export function AdminSettings({ const [showPasswordInput, setShowPasswordInput] = React.useState(false); const [importPassword, setImportPassword] = React.useState(""); + // Only local accounts need to confirm their password before we post the import request. const requiresImportPassword = React.useMemo( () => !currentUser?.is_oidc, [currentUser?.is_oidc], @@ -129,6 +130,7 @@ export function AdminSettings({ toast.error(t("admin.failedToFetchOidcConfig")); } }); + // Capture the current session so we know whether to ask for a password later. getUserInfo() .then((info) => { if (info) { @@ -386,6 +388,7 @@ export function AdminSettings({ const formData = new FormData(); formData.append("file", importFile); if (requiresImportPassword) { + // Preserve the existing password flow for non-OIDC accounts. formData.append("password", importPassword); } @@ -996,6 +999,7 @@ export function AdminSettings({
+ {/* Only render the password field when a local account is performing the import. */} {importFile && requiresImportPassword && (
-- 2.49.1