diff --git a/.env.example b/.env.example index b05d685b1..854c2b19a 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,14 @@ # This file will be committed to version control, so make sure not to have any secrets in it. # If you are cloning this repo, create a copy of this file named `.env` and populate it with your secrets. +# The below secret is not used anywhere but required for Auth.js (Would encrypt JWTs and Mail hashes, both not used) +AUTH_SECRET="supersecret" + +# The below secret is used to encrypt integration secrets in the database. +# It should be a 32-byte string, generated by running `openssl rand -hex 32` on Unix +# or starting the project without any (which will show a randomly generated one). +SECRET_ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000 + # This is how you can use the sqlite driver: DB_DRIVER='better-sqlite3' DB_URL='FULL_PATH_TO_YOUR_SQLITE_DB_FILE' @@ -20,11 +28,6 @@ DB_URL='FULL_PATH_TO_YOUR_SQLITE_DB_FILE' # DB_PASSWORD='password' # DB_NAME='name-of-database' - -# You can generate the secret via 'openssl rand -base64 32' on Unix -# @see https://next-auth.js.org/configuration/options#secret -AUTH_SECRET='supersecret' - TURBO_TELEMETRY_DISABLED=1 # Configure logging to use winston logger diff --git a/.github/workflows/deployment-docker-image.yml b/.github/workflows/deployment-docker-image.yml index b2860a9df..74772e8ef 100644 --- a/.github/workflows/deployment-docker-image.yml +++ b/.github/workflows/deployment-docker-image.yml @@ -13,11 +13,6 @@ on: required: false default: true description: Send notifications - push-image: - type: boolean - required: false - default: true - description: Push Docker Image permissions: contents: write @@ -112,7 +107,6 @@ jobs: NEXT_VERSION: ${{ needs.release.outputs.version }} DEPLOY_LATEST: ${{ github.ref_name == 'main' }} DEPLOY_BETA: ${{ github.ref_name == 'beta' }} - PUSH_IMAGE: ${{ github.event_name != 'workflow_dispatch' || github.events.inputs.push-image == true }} steps: - uses: actions/checkout@v4 with: @@ -143,13 +137,13 @@ jobs: ${{ env.DEPLOY_LATEST == 'true' && 'type=raw,value=latest' || null }} ${{ env.DEPLOY_BETA == 'true' && 'type=raw,value=beta' || null }} type=raw,value=${{ env.NEXT_VERSION }} - - name: Build and maybe push + - name: Build and push id: buildPushAction uses: docker/build-push-action@v6 with: platforms: linux/amd64,linux/arm64 context: . - push: ${{ env.PUSH_IMAGE }} + push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} network: host @@ -160,4 +154,4 @@ jobs: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} uses: Ilshidur/action-discord@master with: - args: "Deployment of image has completed for branch ${{ github.ref_name }}. Image ID is '${{ steps.buildPushAction.outputs.imageid }}'. ${{ env.PUSH_IMAGE == 'true' && '' || 'This was a dry run' }}" + args: "Deployment of image has completed for branch ${{ github.ref_name }}. Image ID is '${{ steps.buildPushAction.outputs.imageid }}'." diff --git a/.vscode/settings.json b/.vscode/settings.json index 2e67df382..51d2500a1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -39,5 +39,5 @@ "i18n-ally.localesPaths": [ "packages/translation/src/lang", ], - "i18n-ally.keystyle": "auto", + "i18n-ally.keystyle": "nested", } diff --git a/Dockerfile b/Dockerfile index 3e6f04281..a799e8152 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,51 +25,41 @@ RUN corepack enable pnpm && pnpm build FROM base AS runner WORKDIR /app -# gettext is required for envsubst -RUN apk add --no-cache redis nginx bash gettext su-exec +# gettext is required for envsubst, openssl for generating AUTH_SECRET, su-exec for running application as non-root +RUN apk add --no-cache redis nginx bash gettext su-exec openssl RUN mkdir /appdata VOLUME /appdata -RUN mkdir /secrets -VOLUME /secrets - - - -RUN addgroup --system --gid 1001 nodejs -RUN adduser --system --uid 1001 nextjs # Enable homarr cli -COPY --from=builder --chown=nextjs:nodejs /app/packages/cli/cli.cjs /app/apps/cli/cli.cjs +COPY --from=builder /app/packages/cli/cli.cjs /app/apps/cli/cli.cjs RUN echo $'#!/bin/bash\ncd /app/apps/cli && node ./cli.cjs "$@"' > /usr/bin/homarr RUN chmod +x /usr/bin/homarr # Don't run production as root -RUN chown -R nextjs:nodejs /secrets -RUN mkdir -p /var/cache/nginx && chown -R nextjs:nodejs /var/cache/nginx && \ - mkdir -p /var/log/nginx && chown -R nextjs:nodejs /var/log/nginx && \ - mkdir -p /var/lib/nginx && chown -R nextjs:nodejs /var/lib/nginx && \ - touch /run/nginx/nginx.pid && chown -R nextjs:nodejs /run/nginx/nginx.pid && \ - mkdir -p /etc/nginx/templates /etc/nginx/ssl/certs && chown -R nextjs:nodejs /etc/nginx +RUN mkdir -p /var/cache/nginx && \ + mkdir -p /var/log/nginx && \ + mkdir -p /var/lib/nginx && \ + touch /run/nginx/nginx.pid && \ + mkdir -p /etc/nginx/templates /etc/nginx/ssl/certs COPY --from=builder /app/apps/nextjs/next.config.mjs . COPY --from=builder /app/apps/nextjs/package.json . -COPY --from=builder --chown=nextjs:nodejs /app/apps/tasks/tasks.cjs ./apps/tasks/tasks.cjs -COPY --from=builder --chown=nextjs:nodejs /app/apps/websocket/wssServer.cjs ./apps/websocket/wssServer.cjs -COPY --from=builder --chown=nextjs:nodejs /app/node_modules/better-sqlite3/build/Release/better_sqlite3.node /app/build/better_sqlite3.node +COPY --from=builder /app/apps/tasks/tasks.cjs ./apps/tasks/tasks.cjs +COPY --from=builder /app/apps/websocket/wssServer.cjs ./apps/websocket/wssServer.cjs +COPY --from=builder /app/node_modules/better-sqlite3/build/Release/better_sqlite3.node /app/build/better_sqlite3.node -COPY --from=builder --chown=nextjs:nodejs /app/packages/db/migrations ./db/migrations +COPY --from=builder /app/packages/db/migrations ./db/migrations # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing -COPY --from=builder --chown=nextjs:nodejs /app/apps/nextjs/.next/standalone ./ -COPY --from=builder --chown=nextjs:nodejs /app/apps/nextjs/.next/static ./apps/nextjs/.next/static -COPY --from=builder --chown=nextjs:nodejs /app/apps/nextjs/public ./apps/nextjs/public -COPY --chown=nextjs:nodejs scripts/run.sh ./run.sh -COPY scripts/entrypoint.sh ./entrypoint.sh -RUN chmod +x ./entrypoint.sh -COPY --chown=nextjs:nodejs scripts/generateRandomSecureKey.js ./generateRandomSecureKey.js -COPY --chown=nextjs:nodejs packages/redis/redis.conf /app/redis.conf -COPY --chown=nextjs:nodejs nginx.conf /etc/nginx/templates/nginx.conf +COPY --from=builder /app/apps/nextjs/.next/standalone ./ +COPY --from=builder /app/apps/nextjs/.next/static ./apps/nextjs/.next/static +COPY --from=builder /app/apps/nextjs/public ./apps/nextjs/public +COPY scripts/run.sh ./run.sh +COPY --chmod=777 scripts/entrypoint.sh ./entrypoint.sh +COPY packages/redis/redis.conf /app/redis.conf +COPY nginx.conf /etc/nginx/templates/nginx.conf ENV DB_URL='/appdata/db/db.sqlite' @@ -78,4 +68,4 @@ ENV DB_DRIVER='better-sqlite3' ENV AUTH_PROVIDERS='credentials' ENTRYPOINT [ "/app/entrypoint.sh" ] -CMD ["sh", "run.sh"] +CMD ["sh", "run.sh"] \ No newline at end of file diff --git a/apps/nextjs/next.config.mjs b/apps/nextjs/next.config.mjs index 8c4bd2800..bd57eb1a2 100644 --- a/apps/nextjs/next.config.mjs +++ b/apps/nextjs/next.config.mjs @@ -1,6 +1,7 @@ // Importing env files here to validate on build import "@homarr/auth/env.mjs"; import "@homarr/db/env.mjs"; +import "@homarr/common/env.mjs"; import MillionLint from "@million/lint"; import createNextIntlPlugin from "next-intl/plugin"; diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json index 6b7a81f36..d9c654358 100644 --- a/apps/nextjs/package.json +++ b/apps/nextjs/package.json @@ -87,7 +87,7 @@ "@types/react": "^19.0.2", "@types/react-dom": "^19.0.2", "@types/swagger-ui-react": "^4.18.3", - "concurrently": "^9.1.1", + "concurrently": "^9.1.2", "eslint": "^9.17.0", "node-loader": "^2.1.0", "prettier": "^3.4.2", diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx index 791be2938..a223e3bfc 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx @@ -3,13 +3,13 @@ import { useCallback } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; -import { Alert, Button, Fieldset, Group, SegmentedControl, Stack, Text, TextInput } from "@mantine/core"; +import { Alert, Button, Checkbox, Fieldset, Group, SegmentedControl, Stack, Text, TextInput } from "@mantine/core"; import { IconInfoCircle } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; import { revalidatePathActionAsync } from "@homarr/common/client"; import type { IntegrationKind, IntegrationSecretKind } from "@homarr/definitions"; -import { getAllSecretKindOptions, getIntegrationName } from "@homarr/definitions"; +import { getAllSecretKindOptions, getIntegrationName, integrationDefs } from "@homarr/definitions"; import type { UseFormReturnType } from "@homarr/form"; import { useZodForm } from "@homarr/form"; import { convertIntegrationTestConnectionError } from "@homarr/integrations/client"; @@ -38,6 +38,7 @@ export const NewIntegrationForm = ({ searchParams }: NewIntegrationFormProps) => kind, value: "", })), + attemptSearchEngineCreation: true, }, }); const { mutateAsync, isPending } = clientApi.integration.create.useMutation(); @@ -78,6 +79,8 @@ export const NewIntegrationForm = ({ searchParams }: NewIntegrationFormProps) => ); }; + const supportsSearchEngine = integrationDefs[searchParams.kind].category.flat().includes("search"); + return (