Compare commits
117 Commits
ssh-cli-do
...
infisical/
Author | SHA1 | Date | |
---|---|---|---|
a74f0170da | |||
a0fad34a6d | |||
0b9d890a51 | |||
5ba507bc1c | |||
0ecc196e5d | |||
ddac9f7cc4 | |||
34354994d8 | |||
1576358805 | |||
e6103d2d3f | |||
8bf8bc77c9 | |||
3219723149 | |||
6d3793beff | |||
0df41f3391 | |||
1acac9d479 | |||
0cefd6f837 | |||
5e9dc0b98d | |||
f632847dc6 | |||
faa6d1cf40 | |||
7fb18870e3 | |||
ae841715e5 | |||
baac87c16a | |||
b726187ba3 | |||
d98ff32b07 | |||
1fa510b32f | |||
c57f0d8120 | |||
00490f2cff | |||
ee58f538c0 | |||
0fa20f7839 | |||
40ef75d3bd | |||
26af13453c | |||
ad1f71883d | |||
2659ea7170 | |||
d2e3f504fd | |||
ca4151a34d | |||
d4bc104fd1 | |||
7e3a3fcdb0 | |||
7f67912d2f | |||
a7f4020c08 | |||
d2d89034ba | |||
2fc6c564c0 | |||
240b86c1d5 | |||
30d66cef89 | |||
b7d11444a9 | |||
0a6aef0afa | |||
0ac7ec460b | |||
808a901aee | |||
d5412f916f | |||
d0648ca596 | |||
3291f1f908 | |||
965d30bd03 | |||
68fe7c589a | |||
54377a44d3 | |||
8c902d7699 | |||
c25c84aeb3 | |||
4359eb7313 | |||
322536d738 | |||
6c5db3a187 | |||
a337e6badd | |||
524a97e9a6 | |||
c56f598115 | |||
19d32a1a3b | |||
7e5417a0eb | |||
afd6de27fe | |||
7781a6b7e7 | |||
b3b4e41d92 | |||
5225f5136a | |||
398adfaf76 | |||
d77c26fa38 | |||
ef7b81734a | |||
09b489a348 | |||
6b5c50def0 | |||
1f2d52176c | |||
7002e297c8 | |||
71864a131f | |||
9964d2ecaa | |||
3ebbaefc2a | |||
dd5c494bdb | |||
bace8af5a1 | |||
f56196b820 | |||
7042d73410 | |||
cb22ee315e | |||
701eb7cfc6 | |||
bf8df14b01 | |||
1ba8b6394b | |||
c442c8483a | |||
0435305a68 | |||
febf11f502 | |||
64fd15c32d | |||
a2c9494d52 | |||
18460e0678 | |||
3d03fece74 | |||
234e7eb9be | |||
04af313bf0 | |||
9b038ccc45 | |||
9beb384546 | |||
12ec9b4b4e | |||
96b8e7fda8 | |||
93b9108aa3 | |||
99017ea1ae | |||
f32588112e | |||
f9b0b6700a | |||
b45d9398f0 | |||
1d1140237f | |||
937560fd8d | |||
5f4b7b9ea7 | |||
05139820a5 | |||
7f6bc3ecfe | |||
d8cc000ad1 | |||
8fc03c06d9 | |||
50ceedf39f | |||
550096e72b | |||
1190ca2d77 | |||
2fb60201bc | |||
634b500244 | |||
54b4d4ae55 | |||
2f6dab3f63 | |||
242595fceb |
8
.github/workflows/check-fe-ts-and-lint.yml
vendored
@ -18,18 +18,18 @@ jobs:
|
||||
steps:
|
||||
- name: ☁️ Checkout source
|
||||
uses: actions/checkout@v3
|
||||
- name: 🔧 Setup Node 16
|
||||
- name: 🔧 Setup Node 20
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16"
|
||||
node-version: "20"
|
||||
cache: "npm"
|
||||
cache-dependency-path: frontend/package-lock.json
|
||||
- name: 📦 Install dependencies
|
||||
run: npm install
|
||||
working-directory: frontend
|
||||
- name: 🏗️ Run Type check
|
||||
run: npm run type:check
|
||||
run: npm run type:check
|
||||
working-directory: frontend
|
||||
- name: 🏗️ Run Link check
|
||||
run: npm run lint:fix
|
||||
run: npm run lint:fix
|
||||
working-directory: frontend
|
||||
|
@ -8,7 +8,7 @@ FROM node:20-slim AS base
|
||||
FROM base AS frontend-dependencies
|
||||
WORKDIR /app
|
||||
|
||||
COPY frontend/package.json frontend/package-lock.json frontend/next.config.js ./
|
||||
COPY frontend/package.json frontend/package-lock.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci --only-production --ignore-scripts
|
||||
@ -23,17 +23,16 @@ COPY --from=frontend-dependencies /app/node_modules ./node_modules
|
||||
COPY /frontend .
|
||||
|
||||
ENV NODE_ENV production
|
||||
ENV NEXT_PUBLIC_ENV production
|
||||
ARG POSTHOG_HOST
|
||||
ENV NEXT_PUBLIC_POSTHOG_HOST $POSTHOG_HOST
|
||||
ENV VITE_POSTHOG_HOST $POSTHOG_HOST
|
||||
ARG POSTHOG_API_KEY
|
||||
ENV NEXT_PUBLIC_POSTHOG_API_KEY $POSTHOG_API_KEY
|
||||
ENV VITE_POSTHOG_API_KEY $POSTHOG_API_KEY
|
||||
ARG INTERCOM_ID
|
||||
ENV NEXT_PUBLIC_INTERCOM_ID $INTERCOM_ID
|
||||
ENV VITE_INTERCOM_ID $INTERCOM_ID
|
||||
ARG INFISICAL_PLATFORM_VERSION
|
||||
ENV NEXT_PUBLIC_INFISICAL_PLATFORM_VERSION $INFISICAL_PLATFORM_VERSION
|
||||
ENV VITE_INFISICAL_PLATFORM_VERSION $INFISICAL_PLATFORM_VERSION
|
||||
ARG CAPTCHA_SITE_KEY
|
||||
ENV NEXT_PUBLIC_CAPTCHA_SITE_KEY $CAPTCHA_SITE_KEY
|
||||
ENV VITE_CAPTCHA_SITE_KEY $CAPTCHA_SITE_KEY
|
||||
|
||||
# Build
|
||||
RUN npm run build
|
||||
@ -44,20 +43,10 @@ WORKDIR /app
|
||||
|
||||
RUN groupadd -r -g 1001 nodejs && useradd -r -u 1001 -g nodejs non-root-user
|
||||
|
||||
RUN mkdir -p /app/.next/cache/images && chown non-root-user:nodejs /app/.next/cache/images
|
||||
VOLUME /app/.next/cache/images
|
||||
|
||||
COPY --chown=non-root-user:nodejs --chmod=555 frontend/scripts ./scripts
|
||||
COPY --from=frontend-builder /app/public ./public
|
||||
RUN chown non-root-user:nodejs ./public/data
|
||||
|
||||
COPY --from=frontend-builder --chown=non-root-user:nodejs /app/.next/standalone ./
|
||||
COPY --from=frontend-builder --chown=non-root-user:nodejs /app/.next/static ./.next/static
|
||||
COPY --from=frontend-builder --chown=non-root-user:nodejs /app/dist ./
|
||||
|
||||
USER non-root-user
|
||||
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
##
|
||||
## BACKEND
|
||||
##
|
||||
@ -137,7 +126,7 @@ RUN apt-get update && apt-get install -y \
|
||||
freetds-dev \
|
||||
freetds-bin \
|
||||
tdsodbc \
|
||||
openssh \
|
||||
openssh-client \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Configure ODBC in production
|
||||
@ -160,14 +149,11 @@ RUN chmod u+rx /usr/sbin/update-ca-certificates
|
||||
|
||||
## set pre baked keys
|
||||
ARG POSTHOG_API_KEY
|
||||
ENV NEXT_PUBLIC_POSTHOG_API_KEY=$POSTHOG_API_KEY \
|
||||
BAKED_NEXT_PUBLIC_POSTHOG_API_KEY=$POSTHOG_API_KEY
|
||||
ENV POSTHOG_API_KEY=$POSTHOG_API_KEY
|
||||
ARG INTERCOM_ID=intercom-id
|
||||
ENV NEXT_PUBLIC_INTERCOM_ID=$INTERCOM_ID \
|
||||
BAKED_NEXT_PUBLIC_INTERCOM_ID=$INTERCOM_ID
|
||||
ENV INTERCOM_ID=$INTERCOM_ID
|
||||
ARG CAPTCHA_SITE_KEY
|
||||
ENV NEXT_PUBLIC_CAPTCHA_SITE_KEY=$CAPTCHA_SITE_KEY \
|
||||
BAKED_NEXT_PUBLIC_CAPTCHA_SITE_KEY=$CAPTCHA_SITE_KEY
|
||||
ENV CAPTCHA_SITE_KEY=$CAPTCHA_SITE_KEY
|
||||
|
||||
WORKDIR /
|
||||
|
||||
@ -192,4 +178,4 @@ EXPOSE 443
|
||||
|
||||
USER non-root-user
|
||||
|
||||
CMD ["./standalone-entrypoint.sh"]
|
||||
CMD ["./standalone-entrypoint.sh"]
|
||||
|
@ -12,7 +12,7 @@ RUN apk add --no-cache libc6-compat
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY frontend/package.json frontend/package-lock.json frontend/next.config.js ./
|
||||
COPY frontend/package.json frontend/package-lock.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci --only-production --ignore-scripts
|
||||
@ -27,17 +27,16 @@ COPY --from=frontend-dependencies /app/node_modules ./node_modules
|
||||
COPY /frontend .
|
||||
|
||||
ENV NODE_ENV production
|
||||
ENV NEXT_PUBLIC_ENV production
|
||||
ARG POSTHOG_HOST
|
||||
ENV NEXT_PUBLIC_POSTHOG_HOST $POSTHOG_HOST
|
||||
ENV VITE_POSTHOG_HOST $POSTHOG_HOST
|
||||
ARG POSTHOG_API_KEY
|
||||
ENV NEXT_PUBLIC_POSTHOG_API_KEY $POSTHOG_API_KEY
|
||||
ENV VITE_POSTHOG_API_KEY $POSTHOG_API_KEY
|
||||
ARG INTERCOM_ID
|
||||
ENV NEXT_PUBLIC_INTERCOM_ID $INTERCOM_ID
|
||||
ENV VITE_INTERCOM_ID $INTERCOM_ID
|
||||
ARG INFISICAL_PLATFORM_VERSION
|
||||
ENV NEXT_PUBLIC_INFISICAL_PLATFORM_VERSION $INFISICAL_PLATFORM_VERSION
|
||||
ENV VITE_INFISICAL_PLATFORM_VERSION $INFISICAL_PLATFORM_VERSION
|
||||
ARG CAPTCHA_SITE_KEY
|
||||
ENV NEXT_PUBLIC_CAPTCHA_SITE_KEY $CAPTCHA_SITE_KEY
|
||||
ENV VITE_CAPTCHA_SITE_KEY $CAPTCHA_SITE_KEY
|
||||
|
||||
# Build
|
||||
RUN npm run build
|
||||
@ -49,20 +48,10 @@ WORKDIR /app
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 non-root-user
|
||||
|
||||
RUN mkdir -p /app/.next/cache/images && chown non-root-user:nodejs /app/.next/cache/images
|
||||
VOLUME /app/.next/cache/images
|
||||
|
||||
COPY --chown=non-root-user:nodejs --chmod=555 frontend/scripts ./scripts
|
||||
COPY --from=frontend-builder /app/public ./public
|
||||
RUN chown non-root-user:nodejs ./public/data
|
||||
|
||||
COPY --from=frontend-builder --chown=non-root-user:nodejs /app/.next/standalone ./
|
||||
COPY --from=frontend-builder --chown=non-root-user:nodejs /app/.next/static ./.next/static
|
||||
COPY --from=frontend-builder --chown=non-root-user:nodejs /app/dist ./
|
||||
|
||||
USER non-root-user
|
||||
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
##
|
||||
## BACKEND
|
||||
##
|
||||
@ -159,14 +148,11 @@ RUN chmod u+rx /usr/sbin/update-ca-certificates
|
||||
|
||||
## set pre baked keys
|
||||
ARG POSTHOG_API_KEY
|
||||
ENV NEXT_PUBLIC_POSTHOG_API_KEY=$POSTHOG_API_KEY \
|
||||
BAKED_NEXT_PUBLIC_POSTHOG_API_KEY=$POSTHOG_API_KEY
|
||||
ENV POSTHOG_API_KEY=$POSTHOG_API_KEY
|
||||
ARG INTERCOM_ID=intercom-id
|
||||
ENV NEXT_PUBLIC_INTERCOM_ID=$INTERCOM_ID \
|
||||
BAKED_NEXT_PUBLIC_INTERCOM_ID=$INTERCOM_ID
|
||||
ENV INTERCOM_ID=$INTERCOM_ID
|
||||
ARG CAPTCHA_SITE_KEY
|
||||
ENV NEXT_PUBLIC_CAPTCHA_SITE_KEY=$CAPTCHA_SITE_KEY \
|
||||
BAKED_NEXT_PUBLIC_CAPTCHA_SITE_KEY=$CAPTCHA_SITE_KEY
|
||||
ENV CAPTCHA_SITE_KEY=$CAPTCHA_SITE_KEY
|
||||
|
||||
|
||||
COPY --from=backend-runner /app /backend
|
||||
@ -189,4 +175,4 @@ EXPOSE 443
|
||||
|
||||
USER non-root-user
|
||||
|
||||
CMD ["./standalone-entrypoint.sh"]
|
||||
CMD ["./standalone-entrypoint.sh"]
|
||||
|
128
backend/package-lock.json
generated
@ -26,6 +26,7 @@
|
||||
"@fastify/rate-limit": "^9.0.0",
|
||||
"@fastify/request-context": "^5.1.0",
|
||||
"@fastify/session": "^10.7.0",
|
||||
"@fastify/static": "^7.0.4",
|
||||
"@fastify/swagger": "^8.14.0",
|
||||
"@fastify/swagger-ui": "^2.1.0",
|
||||
"@google-cloud/kms": "^4.5.0",
|
||||
@ -5406,6 +5407,7 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/accept-negotiator/-/accept-negotiator-1.1.0.tgz",
|
||||
"integrity": "sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
@ -5545,6 +5547,7 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/send/-/send-2.1.0.tgz",
|
||||
"integrity": "sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@lukeed/ms": "^2.0.1",
|
||||
"escape-html": "~1.0.3",
|
||||
@ -5563,16 +5566,85 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/static": {
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/static/-/static-6.12.0.tgz",
|
||||
"integrity": "sha512-KK1B84E6QD/FcQWxDI2aiUCwHxMJBI1KeCUzm1BwYpPY1b742+jeKruGHP2uOluuM6OkBPI8CIANrXcCRtC2oQ==",
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/static/-/static-7.0.4.tgz",
|
||||
"integrity": "sha512-p2uKtaf8BMOZWLs6wu+Ihg7bWNBdjNgCwDza4MJtTqg+5ovKmcbgbR9Xs5/smZ1YISfzKOCNYmZV8LaCj+eJ1Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fastify/accept-negotiator": "^1.0.0",
|
||||
"@fastify/send": "^2.0.0",
|
||||
"content-disposition": "^0.5.3",
|
||||
"fastify-plugin": "^4.0.0",
|
||||
"glob": "^8.0.1",
|
||||
"p-limit": "^3.1.0"
|
||||
"fastq": "^1.17.0",
|
||||
"glob": "^10.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/static/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/static/node_modules/glob": {
|
||||
"version": "10.4.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.1.0",
|
||||
"jackspeak": "^3.1.2",
|
||||
"minimatch": "^9.0.4",
|
||||
"minipass": "^7.1.2",
|
||||
"package-json-from-dist": "^1.0.0",
|
||||
"path-scurry": "^1.11.1"
|
||||
},
|
||||
"bin": {
|
||||
"glob": "dist/esm/bin.mjs"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/static/node_modules/jackspeak": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
|
||||
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"@isaacs/cliui": "^8.0.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@pkgjs/parseargs": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/static/node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/static/node_modules/minipass": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/swagger": {
|
||||
@ -5599,6 +5671,20 @@
|
||||
"yaml": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/swagger-ui/node_modules/@fastify/static": {
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/static/-/static-6.12.0.tgz",
|
||||
"integrity": "sha512-KK1B84E6QD/FcQWxDI2aiUCwHxMJBI1KeCUzm1BwYpPY1b742+jeKruGHP2uOluuM6OkBPI8CIANrXcCRtC2oQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fastify/accept-negotiator": "^1.0.0",
|
||||
"@fastify/send": "^2.0.0",
|
||||
"content-disposition": "^0.5.3",
|
||||
"fastify-plugin": "^4.0.0",
|
||||
"glob": "^8.0.1",
|
||||
"p-limit": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@google-cloud/kms": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@google-cloud/kms/-/kms-4.5.0.tgz",
|
||||
@ -6062,9 +6148,10 @@
|
||||
"integrity": "sha512-O89xFDLW2gBoZWNXuXpBSM32/KealKCTb3JGtJdtUQc7RjAk8XzrRgyz02cPAwGKwKPxy0ivuC7UP9bmN87egQ=="
|
||||
},
|
||||
"node_modules/@lukeed/ms": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.1.tgz",
|
||||
"integrity": "sha512-Xs/4RZltsAL7pkvaNStUQt7netTkyxrS0K+RILcVr3TRMS/ToOg4I6uNfhB9SlGsnWBym4U+EaXq0f0cEMNkHA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.2.tgz",
|
||||
"integrity": "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@ -13879,9 +13966,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
|
||||
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
|
||||
"version": "4.21.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
@ -13903,7 +13990,7 @@
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.10",
|
||||
"path-to-regexp": "0.1.12",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.13.0",
|
||||
"range-parser": "~1.2.1",
|
||||
@ -13918,6 +14005,10 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/express-session": {
|
||||
@ -17388,15 +17479,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.7",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
||||
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
@ -18383,9 +18475,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
|
||||
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/path-type": {
|
||||
|
@ -134,6 +134,7 @@
|
||||
"@fastify/rate-limit": "^9.0.0",
|
||||
"@fastify/request-context": "^5.1.0",
|
||||
"@fastify/session": "^10.7.0",
|
||||
"@fastify/static": "^7.0.4",
|
||||
"@fastify/swagger": "^8.14.0",
|
||||
"@fastify/swagger-ui": "^2.1.0",
|
||||
"@google-cloud/kms": "^4.5.0",
|
||||
|
@ -84,7 +84,10 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
||||
samlConfig.audience = `spn:${ssoConfig.issuer}`;
|
||||
}
|
||||
}
|
||||
if (ssoConfig.authProvider === SamlProviders.GOOGLE_SAML) {
|
||||
if (
|
||||
ssoConfig.authProvider === SamlProviders.GOOGLE_SAML ||
|
||||
ssoConfig.authProvider === SamlProviders.AUTH0_SAML
|
||||
) {
|
||||
samlConfig.wantAssertionsSigned = false;
|
||||
}
|
||||
|
||||
@ -123,7 +126,10 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
||||
`email: ${email} firstName: ${profile.firstName as string}`
|
||||
);
|
||||
|
||||
throw new Error("Invalid saml request. Missing email or first name");
|
||||
throw new BadRequestError({
|
||||
message:
|
||||
"Missing email or first name. Please double check your SAML attribute mapping for the selected provider."
|
||||
});
|
||||
}
|
||||
|
||||
const userMetadata = Object.keys(profile.attributes || {})
|
||||
|
@ -213,7 +213,7 @@ export const accessApprovalRequestServiceFactory = ({
|
||||
);
|
||||
|
||||
const requesterFullName = `${requestedByUser.firstName} ${requestedByUser.lastName}`;
|
||||
const approvalUrl = `${cfg.SITE_URL}/project/${project.id}/approval`;
|
||||
const approvalUrl = `${cfg.SITE_URL}/secret-manager/${project.id}/approval`;
|
||||
|
||||
await triggerSlackNotification({
|
||||
projectId: project.id,
|
||||
|
@ -246,8 +246,7 @@ export const licenseServiceFactory = ({
|
||||
};
|
||||
|
||||
const getOrgPlan = async ({ orgId, actor, actorId, actorOrgId, actorAuthMethod, projectId }: TOrgPlanDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||
await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
||||
const plan = await getPlan(orgId, projectId);
|
||||
return plan;
|
||||
};
|
||||
|
@ -6,7 +6,8 @@ export enum SamlProviders {
|
||||
AZURE_SAML = "azure-saml",
|
||||
JUMPCLOUD_SAML = "jumpcloud-saml",
|
||||
GOOGLE_SAML = "google-saml",
|
||||
KEYCLOAK_SAML = "keycloak-saml"
|
||||
KEYCLOAK_SAML = "keycloak-saml",
|
||||
AUTH0_SAML = "auth0-saml"
|
||||
}
|
||||
|
||||
export type TCreateSamlCfgDTO = {
|
||||
|
@ -36,7 +36,7 @@ export const sendApprovalEmailsFn = async ({
|
||||
firstName: reviewerUser.firstName,
|
||||
projectName: project.name,
|
||||
organizationName: project.organization.name,
|
||||
approvalUrl: `${cfg.SITE_URL}/project/${project.id}/approval?requestId=${secretApprovalRequest.id}`
|
||||
approvalUrl: `${cfg.SITE_URL}/secret-manager/${project.id}/approval?requestId=${secretApprovalRequest.id}`
|
||||
},
|
||||
template: SmtpTemplates.SecretApprovalRequestNeedsReview
|
||||
});
|
||||
|
@ -852,7 +852,7 @@ export const secretApprovalRequestServiceFactory = ({
|
||||
bypassReason,
|
||||
secretPath: policy.secretPath,
|
||||
environment: env.name,
|
||||
approvalUrl: `${cfg.SITE_URL}/project/${project.id}/approval`
|
||||
approvalUrl: `${cfg.SITE_URL}/secret-manager/${project.id}/approval`
|
||||
},
|
||||
template: SmtpTemplates.AccessSecretRequestBypassed
|
||||
});
|
||||
|
@ -157,6 +157,8 @@ const envSchema = z
|
||||
INFISICAL_CLOUD: zodStrBool.default("false"),
|
||||
MAINTENANCE_MODE: zodStrBool.default("false"),
|
||||
CAPTCHA_SECRET: zpStr(z.string().optional()),
|
||||
CAPTCHA_SITE_KEY: zpStr(z.string().optional()),
|
||||
INTERCOM_ID: zpStr(z.string().optional()),
|
||||
|
||||
// TELEMETRY
|
||||
OTEL_TELEMETRY_COLLECTION_ENABLED: zodStrBool.default("false"),
|
||||
|
@ -27,10 +27,10 @@ import { globalRateLimiterCfg } from "./config/rateLimiter";
|
||||
import { addErrorsToResponseSchemas } from "./plugins/add-errors-to-response-schemas";
|
||||
import { apiMetrics } from "./plugins/api-metrics";
|
||||
import { fastifyErrHandler } from "./plugins/error-handler";
|
||||
import { registerExternalNextjs } from "./plugins/external-nextjs";
|
||||
import { serializerCompiler, validatorCompiler, ZodTypeProvider } from "./plugins/fastify-zod";
|
||||
import { fastifyIp } from "./plugins/ip";
|
||||
import { maintenanceMode } from "./plugins/maintenanceMode";
|
||||
import { registerServeUI } from "./plugins/serve-ui";
|
||||
import { fastifySwagger } from "./plugins/swagger";
|
||||
import { registerRoutes } from "./routes";
|
||||
|
||||
@ -120,13 +120,10 @@ export const main = async ({ db, hsmModule, auditLogDb, smtp, logger, queue, key
|
||||
|
||||
await server.register(registerRoutes, { smtp, queue, db, auditLogDb, keyStore, hsmModule });
|
||||
|
||||
if (appCfg.isProductionMode) {
|
||||
await server.register(registerExternalNextjs, {
|
||||
standaloneMode: appCfg.STANDALONE_MODE || IS_PACKAGED,
|
||||
dir: path.join(__dirname, IS_PACKAGED ? "../../../" : "../../"),
|
||||
port: appCfg.PORT
|
||||
});
|
||||
}
|
||||
await server.register(registerServeUI, {
|
||||
standaloneMode: appCfg.STANDALONE_MODE || IS_PACKAGED,
|
||||
dir: path.join(__dirname, IS_PACKAGED ? "../../../" : "../../")
|
||||
});
|
||||
|
||||
await server.ready();
|
||||
server.swagger();
|
||||
|
@ -1,76 +0,0 @@
|
||||
// this plugins allows to run infisical in standalone mode
|
||||
// standalone mode = infisical backend and nextjs frontend in one server
|
||||
// this way users don't need to deploy two things
|
||||
import path from "node:path";
|
||||
|
||||
import { IS_PACKAGED } from "@app/lib/config/env";
|
||||
|
||||
// to enabled this u need to set standalone mode to true
|
||||
export const registerExternalNextjs = async (
|
||||
server: FastifyZodProvider,
|
||||
{
|
||||
standaloneMode,
|
||||
dir,
|
||||
port
|
||||
}: {
|
||||
standaloneMode?: boolean;
|
||||
dir: string;
|
||||
port: number;
|
||||
}
|
||||
) => {
|
||||
if (standaloneMode) {
|
||||
const frontendName = IS_PACKAGED ? "frontend" : "frontend-build";
|
||||
const nextJsBuildPath = path.join(dir, frontendName);
|
||||
|
||||
const { default: conf } = (await import(
|
||||
path.join(dir, `${frontendName}/.next/required-server-files.json`),
|
||||
// @ts-expect-error type
|
||||
{
|
||||
assert: { type: "json" }
|
||||
}
|
||||
)) as { default: { config: string } };
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let NextServer: any;
|
||||
|
||||
if (!IS_PACKAGED) {
|
||||
/* eslint-disable */
|
||||
const { default: nextServer } = (
|
||||
await import(path.join(dir, `${frontendName}/node_modules/next/dist/server/next-server.js`))
|
||||
).default;
|
||||
|
||||
NextServer = nextServer;
|
||||
} else {
|
||||
/* eslint-disable */
|
||||
const nextServer = await import(path.join(dir, `${frontendName}/node_modules/next/dist/server/next-server.js`));
|
||||
|
||||
NextServer = nextServer.default;
|
||||
}
|
||||
|
||||
const nextApp = new NextServer({
|
||||
dev: false,
|
||||
dir: nextJsBuildPath,
|
||||
port,
|
||||
conf: conf.config,
|
||||
hostname: "local",
|
||||
customServer: false
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: ["GET", "PUT", "PATCH", "POST", "DELETE"],
|
||||
url: "/*",
|
||||
schema: {
|
||||
hide: true
|
||||
},
|
||||
handler: (req, res) =>
|
||||
nextApp
|
||||
.getRequestHandler()(req.raw, res.raw)
|
||||
.then(() => {
|
||||
res.hijack();
|
||||
})
|
||||
});
|
||||
server.addHook("onClose", () => nextApp.close());
|
||||
await nextApp.prepare();
|
||||
/* eslint-enable */
|
||||
}
|
||||
};
|
64
backend/src/server/plugins/serve-ui.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import path from "node:path";
|
||||
|
||||
import staticServe from "@fastify/static";
|
||||
|
||||
import { getConfig, IS_PACKAGED } from "@app/lib/config/env";
|
||||
|
||||
// to enabled this u need to set standalone mode to true
|
||||
export const registerServeUI = async (
|
||||
server: FastifyZodProvider,
|
||||
{
|
||||
standaloneMode,
|
||||
dir
|
||||
}: {
|
||||
standaloneMode?: boolean;
|
||||
dir: string;
|
||||
}
|
||||
) => {
|
||||
// use this only for frontend runtime static non-sensitive configuration in standalone mode
|
||||
// that app needs before loading like posthog dsn key
|
||||
// for most of the other usecase use server config
|
||||
server.route({
|
||||
method: "GET",
|
||||
url: "/runtime-ui-env.js",
|
||||
schema: {
|
||||
hide: true
|
||||
},
|
||||
handler: (_req, res) => {
|
||||
const appCfg = getConfig();
|
||||
void res.type("application/javascript");
|
||||
const config = {
|
||||
CAPTCHA_SITE_KEY: appCfg.CAPTCHA_SITE_KEY,
|
||||
POSTHOG_API_KEY: appCfg.POSTHOG_PROJECT_API_KEY,
|
||||
INTERCOM_ID: appCfg.INTERCOM_ID,
|
||||
TELEMETRY_CAPTURING_ENABLED: appCfg.TELEMETRY_ENABLED
|
||||
};
|
||||
const js = `window.__INFISICAL_RUNTIME_ENV__ = Object.freeze(${JSON.stringify(config)});`;
|
||||
void res.send(js);
|
||||
}
|
||||
});
|
||||
|
||||
if (standaloneMode) {
|
||||
const frontendName = IS_PACKAGED ? "frontend" : "frontend-build";
|
||||
const frontendPath = path.join(dir, frontendName);
|
||||
await server.register(staticServe, {
|
||||
root: frontendPath,
|
||||
wildcard: false
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "GET",
|
||||
url: "/*",
|
||||
schema: {
|
||||
hide: true
|
||||
},
|
||||
handler: (request, reply) => {
|
||||
if (request.url.startsWith("/api")) {
|
||||
reply.callNotFound();
|
||||
return;
|
||||
}
|
||||
void reply.sendFile("index.html");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
@ -63,7 +63,8 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
|
||||
schema: {
|
||||
response: {
|
||||
200: z.object({
|
||||
token: z.string()
|
||||
token: z.string(),
|
||||
organizationId: z.string().optional()
|
||||
})
|
||||
}
|
||||
},
|
||||
@ -115,7 +116,7 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
|
||||
{ expiresIn: appCfg.JWT_AUTH_LIFETIME }
|
||||
);
|
||||
|
||||
return { token };
|
||||
return { token, organizationId: decodedToken.organizationId };
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -331,12 +331,8 @@ export const registerSlackRouter = async (server: FastifyZodProvider) => {
|
||||
failureAsync: async () => {
|
||||
return res.redirect(appCfg.SITE_URL as string);
|
||||
},
|
||||
successAsync: async (installation) => {
|
||||
const metadata = JSON.parse(installation.metadata || "") as {
|
||||
orgId: string;
|
||||
};
|
||||
|
||||
return res.redirect(`${appCfg.SITE_URL}/org/${metadata.orgId}/settings?selectedTab=workflow-integrations`);
|
||||
successAsync: async () => {
|
||||
return res.redirect(`${appCfg.SITE_URL}/organization/settings?selectedTab=workflow-integrations`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -305,10 +305,16 @@ const syncSecretsAzureAppConfig = async ({
|
||||
value: string;
|
||||
}
|
||||
|
||||
const getCompleteAzureAppConfigValues = async (url: string) => {
|
||||
if (!integration.app || !integration.app.endsWith(".azconfig.io"))
|
||||
throw new BadRequestError({
|
||||
message: "Invalid Azure App Configuration URL provided."
|
||||
});
|
||||
|
||||
const getCompleteAzureAppConfigValues = async (baseURL: string, url: string) => {
|
||||
let result: AzureAppConfigKeyValue[] = [];
|
||||
while (url) {
|
||||
const res = await request.get(url, {
|
||||
baseURL,
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`
|
||||
},
|
||||
@ -319,7 +325,7 @@ const syncSecretsAzureAppConfig = async ({
|
||||
});
|
||||
|
||||
result = result.concat(res.data.items);
|
||||
url = res.data.nextLink;
|
||||
url = res.data?.["@nextLink"];
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -327,11 +333,13 @@ const syncSecretsAzureAppConfig = async ({
|
||||
|
||||
const metadata = IntegrationMetadataSchema.parse(integration.metadata);
|
||||
|
||||
const azureAppConfigValuesUrl = `${integration.app}/kv?api-version=2023-11-01&key=${metadata.secretPrefix}*${
|
||||
metadata.azureLabel ? `&label=${metadata.azureLabel}` : ""
|
||||
const azureAppConfigValuesUrl = `/kv?api-version=2023-11-01&key=${metadata.secretPrefix}*${
|
||||
metadata.azureLabel ? `&label=${metadata.azureLabel}` : "&label=%00"
|
||||
}`;
|
||||
|
||||
const azureAppConfigSecrets = (await getCompleteAzureAppConfigValues(azureAppConfigValuesUrl)).reduce(
|
||||
const azureAppConfigSecrets = (
|
||||
await getCompleteAzureAppConfigValues(integration.app, azureAppConfigValuesUrl)
|
||||
).reduce(
|
||||
(accum, entry) => {
|
||||
accum[entry.key] = entry.value;
|
||||
|
||||
@ -1159,7 +1167,8 @@ const syncSecretsAWSSecretManager = async ({
|
||||
} else {
|
||||
await secretsManager.send(
|
||||
new DeleteSecretCommand({
|
||||
SecretId: secretId
|
||||
SecretId: secretId,
|
||||
ForceDeleteWithoutRecovery: true
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ const buildSlackPayload = (notification: TSlackNotification) => {
|
||||
*Environment*: ${payload.environment}
|
||||
*Secret path*: ${payload.secretPath || "/"}
|
||||
|
||||
View the complete details <${appCfg.SITE_URL}/project/${payload.projectId}/approval?requestId=${
|
||||
View the complete details <${appCfg.SITE_URL}/secret-manager/${payload.projectId}/approval?requestId=${
|
||||
payload.requestId
|
||||
}|here>.`;
|
||||
|
||||
|
@ -19,7 +19,7 @@ Every new joiner has an onboarding buddy who should ideally be in the the same t
|
||||
1. Join the weekly all-hands meeting. It typically happens on Monday's at 8:30am PT.
|
||||
2. Ship something together on day one – even if tiny! It feels great to hit the ground running, with a development environment all ready to go.
|
||||
3. Check out the [Areas of Responsibility (AoR) Table](https://docs.google.com/spreadsheets/d/1RnXlGFg83Sgu0dh7ycuydsSobmFfI3A0XkGw7vrVxEI/edit?usp=sharing). This is helpful to know who you can ask about particular areas of Infisical. Feel free to add yourself to the areas you'd be most interesting to dive into.
|
||||
4. Read the [Infisical Strategy Doc](https://docs.google.com/document/d/1RaJd3RoS2QpWLFHlgfHaXnHqCCwRt6mCGZkbJ75J_D0/edit?usp=sharing).
|
||||
4. Read the [Infisical Strategy Doc](https://docs.google.com/document/d/1uV9IaahYwbZ5OuzDTFdQMSa1P0mpMOnetGB-xqf4G40).
|
||||
5. Update your LinkedIn profile with one of [Infisical's official banners](https://drive.google.com/drive/u/0/folders/1oSNWjbpRl9oNYwxM_98IqzKs9fAskrb2) (if you want to). You can also coordinate your social posts in the #marketing Slack channel, so that we can boost it from Infisical's official social media accounts.
|
||||
6. Over the first few weeks, feel free to schedule 1:1s with folks on the team to get to know them a bit better.
|
||||
7. Change your Slack username in the users channel to `[NAME] (Infisical)`.
|
||||
|
@ -144,9 +144,6 @@ services:
|
||||
- ./frontend/src:/app/src/ # mounted whole src to avoid missing reload on new files
|
||||
- ./frontend/public:/app/public
|
||||
env_file: .env
|
||||
environment:
|
||||
- NEXT_PUBLIC_ENV=development
|
||||
- INFISICAL_TELEMETRY_ENABLED=false
|
||||
|
||||
pgadmin:
|
||||
image: dpage/pgadmin4
|
||||
|
@ -4,6 +4,13 @@ sidebarTitle: "Overview"
|
||||
description: "Learn how to generate secrets dynamically on-demand."
|
||||
---
|
||||
|
||||
<Info>
|
||||
Note that Dynamic Secrets is a paid feature.
|
||||
|
||||
If you're using Infisical Cloud, then it is available under the **Enterprise Tier**
|
||||
If you're self-hosting Infisical, then you should contact sales@infisical.com to purchase an enterprise license to use it.
|
||||
</Info>
|
||||
|
||||
## Introduction
|
||||
|
||||
Contrary to static key-value secrets, which require manual input of data into the secure Infisical storage, **dynamic secrets are generated on-demand upon access**.
|
||||
|
@ -3,6 +3,13 @@ title: "Approval Workflows"
|
||||
description: "Learn how to enable a set of policies to manage changes to sensitive secrets and environments."
|
||||
---
|
||||
|
||||
<Info>
|
||||
Approval Workflows is a paid feature.
|
||||
|
||||
If you're using Infisical Cloud, then it is available under the **Pro Tier** and **Enterprise Tire**.
|
||||
If you're self-hosting Infisical, then you should contact sales@infisical.com to purchase an enterprise license to use it.
|
||||
</Info>
|
||||
|
||||
## Problem at hand
|
||||
|
||||
Updating secrets in high-stakes environments (e.g., production) can have a number of problematic issues:
|
||||
@ -40,4 +47,4 @@ When a user submits a change to an enviropnment that is under a particular polic
|
||||
|
||||
Approvers are notified by email and/or Slack as soon as the request is initiated. In the Infisical Dashboard, they will be able to `approve` and `merge` (or `deny`) a request for a change in a particular environment. After that, depending on the workflows setup, the change will be automatically propagated to the right applications (e.g., using [Infisical Kubernetes Operator](https://infisical.com/docs/integrations/platforms/kubernetes)).
|
||||
|
||||

|
||||

|
||||
|
@ -15,7 +15,7 @@ Prerequisites:
|
||||
|
||||
<Steps>
|
||||
<Step title="Create a SCIM token in Infisical">
|
||||
In Infisical, head to your Organization Settings > Authentication > SCIM Configuration and
|
||||
In Infisical, head to your Organization Settings > Security > SCIM Configuration and
|
||||
press the **Enable SCIM provisioning** toggle to allow Azure to provision/deprovision users for your organization.
|
||||
|
||||

|
||||
|
@ -15,7 +15,7 @@ Prerequisites:
|
||||
|
||||
<Steps>
|
||||
<Step title="Create a SCIM token in Infisical">
|
||||
In Infisical, head to your Organization Settings > Authentication > SCIM Configuration and
|
||||
In Infisical, head to your Organization Settings > Security > SCIM Configuration and
|
||||
press the **Enable SCIM provisioning** toggle to allow JumpCloud to provision/deprovision users and user groups for your organization.
|
||||
|
||||

|
||||
|
@ -15,7 +15,7 @@ Prerequisites:
|
||||
|
||||
<Steps>
|
||||
<Step title="Create a SCIM token in Infisical">
|
||||
In Infisical, head to your Organization Settings > Authentication > SCIM Configuration and
|
||||
In Infisical, head to your Organization Settings > Security > SCIM Configuration and
|
||||
press the **Enable SCIM provisioning** toggle to allow Okta to provision/deprovision users and user groups for your organization.
|
||||
|
||||

|
||||
|
93
docs/documentation/platform/sso/auth0-saml.mdx
Normal file
@ -0,0 +1,93 @@
|
||||
---
|
||||
title: "Auth0 SAML"
|
||||
description: "Learn how to configure Auth0 SAML for Infisical SSO."
|
||||
---
|
||||
|
||||
<Info>
|
||||
Auth0 SAML SSO feature is a paid feature. If you're using Infisical Cloud,
|
||||
then it is available under the **Pro Tier**. If you're self-hosting Infisical,
|
||||
then you should contact sales@infisical.com to purchase an enterprise license
|
||||
to use it.
|
||||
</Info>
|
||||
|
||||
<Steps>
|
||||
<Step title="Prepare the SAML SSO configuration in Infisical">
|
||||
In Infisical, head to Organization Settings > Security and click **Connect** for SAML under the Connect to an Identity Provider section. Select Auth0, then click **Connect** again.
|
||||
|
||||
Next, note the **Application Callback URL** and **Audience** to use when configuring the Auth0 SAML application.
|
||||
|
||||

|
||||
|
||||
</Step>
|
||||
<Step title="Create a SAML application in Auth0">
|
||||
2.1. In your Auth0 account, head to Applications and create an application.
|
||||
|
||||

|
||||
|
||||
Select **Regular Web Application** and press **Create**.
|
||||
|
||||

|
||||
|
||||
2.2. In the Application head to Settings > Application URIs and add the **Application Callback URL** from step 1 into the **Allowed Callback URLs** field.
|
||||
|
||||

|
||||
|
||||
2.3. In the Application head to Addons > SAML2 Web App and copy the **Issuer**, **Identity Provider Login URL**, and **Identity Provider Certificate** from the **Usage** tab.
|
||||
|
||||

|
||||
|
||||
2.4. Back in Infisical, set **Issuer**, **Identity Provider Login URL**, and **Certificate** to the corresponding items from step 2.3.
|
||||
|
||||

|
||||
|
||||
2.5. Back in Auth0, in the **Settings** tab, set the **Application Callback URL** to the **Application Callback URL** from step 1
|
||||
and update the **Settings** field with the JSON under the picture below (replacing `<audience-from-infisical>` with the **Audience** from step 1).
|
||||
|
||||

|
||||
|
||||
```json
|
||||
{
|
||||
"audience": "<audience-from-infisical>",
|
||||
"mappings": {
|
||||
"email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/email",
|
||||
"given_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/firstName",
|
||||
"family_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/lastName"
|
||||
},
|
||||
"signatureAlgorithm": "rsa-sha256",
|
||||
"digestAlgorithm": "sha256",
|
||||
"signResponse": true
|
||||
}
|
||||
```
|
||||
|
||||
Click **Save**.
|
||||
</Step>
|
||||
<Step title="Enable SAML SSO in Infisical">
|
||||
Enabling SAML SSO allows members in your organization to log into Infisical via Auth0.
|
||||
|
||||

|
||||
</Step>
|
||||
<Step title="Enforce SAML SSO in Infisical">
|
||||
Enforcing SAML SSO ensures that members in your organization can only access Infisical
|
||||
by logging into the organization via Auth0.
|
||||
|
||||
To enforce SAML SSO, you're required to test out the SAML connection by successfully authenticating at least one Auth0 user with Infisical;
|
||||
Once you've completed this requirement, you can toggle the **Enforce SAML SSO** button to enforce SAML SSO.
|
||||
</Step>
|
||||
|
||||
</Steps>
|
||||
|
||||
<Tip>
|
||||
If you are only using one organization on your Infisical instance, you can configure a default organization in the [Server Admin Console](../admin-panel/server-admin#default-organization) to expedite SAML login.
|
||||
</Tip>
|
||||
|
||||
<Note>
|
||||
If you're configuring SAML SSO on a self-hosted instance of Infisical, make
|
||||
sure to set the `AUTH_SECRET` and `SITE_URL` environment variable for it to
|
||||
work:
|
||||
<div class="height:1px;"/>
|
||||
- `AUTH_SECRET`: A secret key used for signing and verifying JWT. This
|
||||
can be a random 32-byte base64 string generated with `openssl rand -base64
|
||||
32`.
|
||||
<div class="height:1px;"/>
|
||||
- `SITE_URL`: The absolute URL of your self-hosted instance of Infisical including the protocol (e.g. https://app.infisical.com)
|
||||
</Note>
|
@ -12,7 +12,7 @@ description: "Learn how to configure Microsoft Entra ID for Infisical SSO."
|
||||
|
||||
<Steps>
|
||||
<Step title="Prepare the SAML SSO configuration in Infisical">
|
||||
In Infisical, head to your Organization Settings > Authentication > SAML SSO Configuration and select **Set up SAML SSO**.
|
||||
In Infisical, head to Organization Settings > Security and click **Connect** for SAML under the Connect to an Identity Provider section. Select Azure / Entra, then click **Connect** again.
|
||||
|
||||
Next, copy the **Reply URL (Assertion Consumer Service URL)** and **Identifier (Entity ID)** to use when configuring the Azure SAML application.
|
||||
|
||||
|
@ -12,7 +12,7 @@ description: "Learn how to configure Google SAML for Infisical SSO."
|
||||
|
||||
<Steps>
|
||||
<Step title="Prepare the SAML SSO configuration in Infisical">
|
||||
In Infisical, head to your Organization Settings > Authentication > SAML SSO Configuration and select **Set up SAML SSO**.
|
||||
In Infisical, head to Organization Settings > Security and click **Connect** for SAML under the Connect to an Identity Provider section. Select Google, then click **Connect** again.
|
||||
|
||||
Next, note the **ACS URL** and **SP Entity ID** to use when configuring the Google SAML application.
|
||||
|
||||
|
@ -12,7 +12,7 @@ description: "Learn how to configure JumpCloud SAML for Infisical SSO."
|
||||
|
||||
<Steps>
|
||||
<Step title="Prepare the SAML SSO configuration in Infisical">
|
||||
In Infisical, head to your Organization Settings > Authentication > SAML SSO Configuration and select **Set up SAML SSO**.
|
||||
In Infisical, head to Organization Settings > Security and click **Connect** for SAML under the Connect to an Identity Provider section. Select JumpCloud, then click **Connect** again.
|
||||
|
||||
Next, copy the **ACS URL** and **SP Entity ID** to use when configuring the JumpCloud SAML application.
|
||||
|
||||
|
@ -12,7 +12,7 @@ description: "Learn how to configure Keycloak SAML for Infisical SSO."
|
||||
|
||||
<Steps>
|
||||
<Step title="Prepare the SAML SSO configuration in Infisical">
|
||||
In Infisical, head to your Organization Settings > Authentication > SAML SSO Configuration and select **Manage**.
|
||||
In Infisical, head to Organization Settings > Security and click **Connect** for SAML under the Connect to an Identity Provider section. Select Keycloak, then click **Connect** again.
|
||||
|
||||

|
||||
|
||||
|
@ -12,7 +12,7 @@ description: "Learn how to configure Okta SAML 2.0 for Infisical SSO."
|
||||
|
||||
<Steps>
|
||||
<Step title="Prepare the SAML SSO configuration in Infisical">
|
||||
In Infisical, head to your Organization Settings > Authentication > SAML SSO Configuration and select **Set up SAML SSO**.
|
||||
In Infisical, head to Organization Settings > Security and click **Connect** for SAML under the Connect to an Identity Provider section. Select Okta, then click **Connect** again.
|
||||
|
||||
Next, copy the **Single sign-on URL** and **Audience URI (SP Entity ID)** to use when configuring the Okta SAML 2.0 application.
|
||||

|
||||
|
@ -28,6 +28,7 @@ Infisical supports these and many other identity providers:
|
||||
- [JumpCloud SAML](/documentation/platform/sso/jumpcloud)
|
||||
- [Keycloak SAML](/documentation/platform/sso/keycloak-saml)
|
||||
- [Google SAML](/documentation/platform/sso/google-saml)
|
||||
- [Auth0 SAML](/documentation/platform/sso/auth0-saml)
|
||||
- [Keycloak OIDC](/documentation/platform/sso/keycloak-oidc)
|
||||
- [Auth0 OIDC](/documentation/platform/sso/auth0-oidc)
|
||||
- [General OIDC](/documentation/platform/sso/general-oidc)
|
||||
|
Before Width: | Height: | Size: 554 KiB After Width: | Height: | Size: 795 KiB |
After Width: | Height: | Size: 493 KiB |
BIN
docs/images/sso/auth0-saml/auth0-config-2.png
Normal file
After Width: | Height: | Size: 612 KiB |
BIN
docs/images/sso/auth0-saml/auth0-config-3.png
Normal file
After Width: | Height: | Size: 366 KiB |
BIN
docs/images/sso/auth0-saml/auth0-config.png
Normal file
After Width: | Height: | Size: 431 KiB |
BIN
docs/images/sso/auth0-saml/create-application-2.png
Normal file
After Width: | Height: | Size: 352 KiB |
BIN
docs/images/sso/auth0-saml/create-application.png
Normal file
After Width: | Height: | Size: 253 KiB |
BIN
docs/images/sso/auth0-saml/enable-saml.png
Normal file
After Width: | Height: | Size: 605 KiB |
BIN
docs/images/sso/auth0-saml/infisical-config.png
Normal file
After Width: | Height: | Size: 605 KiB |
BIN
docs/images/sso/auth0-saml/init-config.png
Normal file
After Width: | Height: | Size: 539 KiB |
@ -29,6 +29,36 @@ description: "How to sync secrets from Infisical to Azure App Configuration"
|
||||

|
||||
|
||||
Press create integration to start syncing secrets to Azure App Configuration.
|
||||
|
||||
<Note>
|
||||
The Azure App Configuration integration requires the following permissions to be set on the user / service principal
|
||||
for Infisical to sync secrets to Azure App Configuration: `Read Key-Value`, `Write Key-Value`, `Delete Key-Value`.
|
||||
|
||||
Any role with these permissions would work such as the **App Configuration Data Owner** role. Alternatively, you can use the
|
||||
**App Configuration Data Reader** role for read-only access or **App Configuration Data Contributor** role for read/write access.
|
||||
</Note>
|
||||
|
||||
</Step>
|
||||
<Step title="Additional Configuration">
|
||||
|
||||
#### Azure references
|
||||
When adding secrets in Infisical that reference Azure Key Vault secrets, Infisical will automatically sets the content type to `application/vnd.microsoft.appconfig.keyvaultref+json;charset=utf-8` in Azure App Configuration.
|
||||
The following reference formats are automatically detected when added on Infisical's side:
|
||||
- `{ "uri": "https://my-key-vault.vault.azure.net/secrets/my-secret" }`
|
||||
- `https://my-key-vault.vault.azure.net/secrets/my-secret`
|
||||
|
||||
#### Azure Labels
|
||||
You can sync secrets from Infisical to Azure with custom labels by enabling the `Use Labels` option during setup:
|
||||
|
||||
**When enabled**: Secrets will be pushed to Azure with your specified label
|
||||
|
||||
**When disabled**: Secrets will be pushed with an empty (null) label
|
||||
|
||||
<Info>
|
||||
If you have set the initial sync to `import` have behavior, the label selection affects which secrets are imported from Azure:
|
||||
- With `Use Labels` disabled: Only secrets with empty labels are imported on initial sync
|
||||
- With `Use Labels` enabled: Only secrets matching your specified label are imported on initial sync
|
||||
</Info>
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
|
@ -17,6 +17,10 @@ description: "How to sync secrets from Infisical to Azure Key Vault"
|
||||

|
||||
|
||||
Press on the Azure Key Vault tile and grant Infisical access to Azure Key Vault.
|
||||
You can optionally authenticate against a specific tenant by providing the Azure tenant or directory ID.
|
||||
|
||||

|
||||
|
||||
</Step>
|
||||
<Step title="Start integration">
|
||||
Obtain the Vault URI of your key vault in the Overview tab.
|
||||
|
@ -248,6 +248,7 @@
|
||||
"documentation/platform/sso/jumpcloud",
|
||||
"documentation/platform/sso/keycloak-saml",
|
||||
"documentation/platform/sso/google-saml",
|
||||
"documentation/platform/sso/auth0-saml",
|
||||
"documentation/platform/sso/keycloak-oidc",
|
||||
"documentation/platform/sso/auth0-oidc",
|
||||
"documentation/platform/sso/general-oidc"
|
||||
@ -342,14 +343,6 @@
|
||||
"cli/faq"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "App Connections",
|
||||
"pages": [
|
||||
"integrations/app-connections/overview",
|
||||
"integrations/app-connections/aws",
|
||||
"integrations/app-connections/github"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Infrastructure Integrations",
|
||||
"pages": [
|
||||
@ -766,33 +759,6 @@
|
||||
"api-reference/endpoints/identity-specific-privilege/list"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "App Connections",
|
||||
"pages": [
|
||||
"api-reference/endpoints/app-connections/list",
|
||||
"api-reference/endpoints/app-connections/options",
|
||||
{ "group": "AWS",
|
||||
"pages": [
|
||||
"api-reference/endpoints/app-connections/aws/list",
|
||||
"api-reference/endpoints/app-connections/aws/get-by-id",
|
||||
"api-reference/endpoints/app-connections/aws/get-by-name",
|
||||
"api-reference/endpoints/app-connections/aws/create",
|
||||
"api-reference/endpoints/app-connections/aws/update",
|
||||
"api-reference/endpoints/app-connections/aws/delete"
|
||||
]
|
||||
},
|
||||
{ "group": "GitHub",
|
||||
"pages": [
|
||||
"api-reference/endpoints/app-connections/github/list",
|
||||
"api-reference/endpoints/app-connections/github/get-by-id",
|
||||
"api-reference/endpoints/app-connections/github/get-by-name",
|
||||
"api-reference/endpoints/app-connections/github/create",
|
||||
"api-reference/endpoints/app-connections/github/update",
|
||||
"api-reference/endpoints/app-connections/github/delete"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Integrations",
|
||||
"pages": [
|
||||
@ -975,9 +941,6 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"integrations": {
|
||||
"intercom": "hsg644ru"
|
||||
},
|
||||
"analytics": {
|
||||
"koala": {
|
||||
"publicApiKey": "pk_b50d7184e0e39ddd5cdb43cf6abeadd9b97d"
|
||||
|
@ -1,3 +1,2 @@
|
||||
node_modules
|
||||
**/.next
|
||||
.next
|
||||
dist
|
||||
|
@ -1,108 +0,0 @@
|
||||
module.exports = {
|
||||
overrides: [
|
||||
{
|
||||
files: ["next.config.js"]
|
||||
}
|
||||
],
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
es6: true
|
||||
},
|
||||
extends: [
|
||||
"airbnb",
|
||||
"airbnb-typescript",
|
||||
"airbnb/hooks",
|
||||
"plugin:react/recommended",
|
||||
"prettier",
|
||||
"plugin:storybook/recommended"
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
project: "./tsconfig.json",
|
||||
ecmaFeatures: {
|
||||
jsx: true
|
||||
},
|
||||
tsconfigRootDir: __dirname
|
||||
},
|
||||
plugins: ["react", "prettier", "simple-import-sort", "import"],
|
||||
rules: {
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
quotes: ["error", "double", { avoidEscape: true }],
|
||||
"comma-dangle": ["error", "only-multiline"],
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"import/prefer-default-export": "off",
|
||||
"react-hooks/exhaustive-deps": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "warn",
|
||||
"react/jsx-props-no-spreading": "off", // switched off for component building
|
||||
// TODO: This rule will be switched ON after complete revamp of frontend
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"jsx-a11y/control-has-associated-label": "off",
|
||||
"no-console": "off",
|
||||
"arrow-body-style": "off",
|
||||
"no-underscore-dangle": [
|
||||
"error",
|
||||
{
|
||||
allow: ["_id"]
|
||||
}
|
||||
],
|
||||
"jsx-a11y/anchor-is-valid": "off",
|
||||
// all those <a> tags must be converted to label or a p component
|
||||
//
|
||||
"react/require-default-props": "off",
|
||||
"react/jsx-filename-extension": [
|
||||
1,
|
||||
{
|
||||
extensions: [".tsx", ".ts"]
|
||||
}
|
||||
],
|
||||
// TODO: turn this rule ON after migration. everything should use arrow functions
|
||||
"react/function-component-definition": [
|
||||
0,
|
||||
{
|
||||
namedComponents: "arrow-function"
|
||||
}
|
||||
],
|
||||
"react/no-unknown-property": [
|
||||
"error",
|
||||
{
|
||||
ignore: ["jsx"]
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"simple-import-sort/exports": "warn",
|
||||
"simple-import-sort/imports": [
|
||||
"warn",
|
||||
{
|
||||
groups: [
|
||||
// Node.js builtins. You could also generate this regex if you use a `.js` config.
|
||||
// For example: `^(${require("module").builtinModules.join("|")})(/|$)`
|
||||
// Note that if you use the `node:` prefix for Node.js builtins,
|
||||
// you can avoid this complexity: You can simply use "^node:".
|
||||
[
|
||||
"^(assert|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|https|module|net|os|path|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|tty|url|util|vm|zlib|freelist|v8|process|async_hooks|http2|perf_hooks)(/.*|$)"
|
||||
],
|
||||
// Packages `react` related packages
|
||||
["^react", "^next", "^@?\\w"],
|
||||
["^@app"],
|
||||
// Internal packages.
|
||||
["^~(/.*|$)"],
|
||||
// Relative imports
|
||||
["^\\.\\.(?!/?$)", "^\\.\\./?$", "^\\./(?=.*/)(?!/?$)", "^\\.(?!/?$)", "^\\./?$"],
|
||||
// Style imports.
|
||||
["^.+\\.?(css|scss)$"]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
ignorePatterns: ["next.config.js", "cypress/**/*.js", "cypress.config.js"],
|
||||
settings: {
|
||||
"import/resolver": {
|
||||
typescript: {
|
||||
project: ["./tsconfig.json"]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
50
frontend/.gitignore
vendored
@ -1,36 +1,24 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
.env
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
||||
# debug
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.vercel
|
||||
.env.infisical
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
.vscode
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
@ -3,5 +3,8 @@
|
||||
"printWidth": 100,
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 2,
|
||||
"semi": true
|
||||
"semi": true,
|
||||
"plugins": ["prettier-plugin-tailwindcss"],
|
||||
"tailwindStylesheet": "./src/index.css",
|
||||
"tailwindFunctions": ["clsx", "twMerge"]
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
const path = require("path");
|
||||
module.exports = {
|
||||
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
|
||||
addons: [
|
||||
"@storybook/addon-links",
|
||||
"@storybook/addon-essentials",
|
||||
"@storybook/addon-interactions",
|
||||
"storybook-dark-mode",
|
||||
{
|
||||
name: "@storybook/addon-styling",
|
||||
options: {
|
||||
postCss: {
|
||||
implementation: require("postcss")
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
framework: {
|
||||
name: "@storybook/nextjs",
|
||||
options: {}
|
||||
},
|
||||
core: {
|
||||
disableTelemetry: true
|
||||
},
|
||||
docs: {
|
||||
autodocs: "tag"
|
||||
}
|
||||
};
|
@ -1,29 +0,0 @@
|
||||
import { themes } from "@storybook/theming";
|
||||
import "react-day-picker/dist/style.css";
|
||||
import "../src/styles/globals.css";
|
||||
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
backgrounds: {
|
||||
default: "dark",
|
||||
values: [
|
||||
{
|
||||
name: "dark",
|
||||
value: "rgb(14, 16, 20)"
|
||||
},
|
||||
{
|
||||
name: "paper",
|
||||
value: "rgb(30, 31, 34)"
|
||||
}
|
||||
]
|
||||
},
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/
|
||||
}
|
||||
},
|
||||
darkMode: {
|
||||
dark: { ...themes.dark, appContentBg: "rgb(14,16,20)", appBg: "rgb(14,16,20)" }
|
||||
}
|
||||
};
|
@ -1,84 +0,0 @@
|
||||
ARG POSTHOG_HOST=https://app.posthog.com
|
||||
ARG POSTHOG_API_KEY=posthog-api-key
|
||||
ARG INTERCOM_ID=intercom-id
|
||||
ARG NEXT_INFISICAL_PLATFORM_VERSION=next-infisical-platform-version
|
||||
ARG CAPTCHA_SITE_KEY=captcha-site-key
|
||||
|
||||
FROM node:16-alpine AS deps
|
||||
# Install dependencies only when needed. Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||
# RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
# Copy over dependency files
|
||||
COPY package.json package-lock.json next.config.js ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci --only-production --ignore-scripts
|
||||
|
||||
# Rebuild the source code only when needed
|
||||
FROM node:16-alpine AS builder
|
||||
WORKDIR /app
|
||||
|
||||
# Copy dependencies
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
# Copy all files
|
||||
COPY . .
|
||||
|
||||
ENV NODE_ENV production
|
||||
ENV NEXT_PUBLIC_ENV production
|
||||
ARG POSTHOG_HOST
|
||||
ENV NEXT_PUBLIC_POSTHOG_HOST $POSTHOG_HOST
|
||||
ARG POSTHOG_API_KEY
|
||||
ENV NEXT_PUBLIC_POSTHOG_API_KEY $POSTHOG_API_KEY
|
||||
ARG INTERCOM_ID
|
||||
ENV NEXT_PUBLIC_INTERCOM_ID $INTERCOM_ID
|
||||
ARG CAPTCHA_SITE_KEY
|
||||
ENV NEXT_PUBLIC_CAPTCHA_SITE_KEY $CAPTCHA_SITE_KEY
|
||||
|
||||
# Build
|
||||
RUN npm run build
|
||||
|
||||
|
||||
# Production image
|
||||
FROM node:16-alpine AS runner
|
||||
WORKDIR /app
|
||||
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
|
||||
RUN mkdir -p /app/.next/cache/images && chown nextjs:nodejs /app/.next/cache/images
|
||||
VOLUME /app/.next/cache/images
|
||||
|
||||
ARG POSTHOG_API_KEY
|
||||
ENV NEXT_PUBLIC_POSTHOG_API_KEY=$POSTHOG_API_KEY \
|
||||
BAKED_NEXT_PUBLIC_POSTHOG_API_KEY=$POSTHOG_API_KEY
|
||||
ARG INTERCOM_ID
|
||||
ENV NEXT_PUBLIC_INTERCOM_ID=$INTERCOM_ID \
|
||||
BAKED_NEXT_PUBLIC_INTERCOM_ID=$INTERCOM_ID
|
||||
ARG SAML_ORG_SLUG
|
||||
ENV NEXT_PUBLIC_SAML_ORG_SLUG=$SAML_ORG_SLUG \
|
||||
BAKED_NEXT_PUBLIC_SAML_ORG_SLUG=$SAML_ORG_SLUG
|
||||
ARG NEXT_INFISICAL_PLATFORM_VERSION
|
||||
ENV NEXT_PUBLIC_INFISICAL_PLATFORM_VERSION=$NEXT_INFISICAL_PLATFORM_VERSION
|
||||
ARG CAPTCHA_SITE_KEY
|
||||
ENV NEXT_PUBLIC_CAPTCHA_SITE_KEY=$CAPTCHA_SITE_KEY \
|
||||
BAKED_NEXT_PUBLIC_CAPTCHA_SITE_KEY=$CAPTCHA_SITE_KEY
|
||||
COPY --chown=nextjs:nodejs --chmod=555 scripts ./scripts
|
||||
COPY --from=builder /app/public ./public
|
||||
RUN chown nextjs:nodejs ./public/data
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs --chmod=777 /app/.next/static ./.next/static
|
||||
RUN chmod -R 777 /app/.next/server
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENV PORT 3000
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
HEALTHCHECK --interval=10s --timeout=3s --start-period=10s \
|
||||
CMD node scripts/healthcheck.js
|
||||
|
||||
|
||||
CMD ["/app/scripts/start.sh"]
|
@ -1,5 +1,5 @@
|
||||
# Base layer
|
||||
FROM node:16-alpine
|
||||
FROM node:20-alpine
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /app
|
||||
@ -11,9 +11,6 @@ COPY package-lock.json ./
|
||||
# Install
|
||||
RUN npm install --ignore-scripts
|
||||
|
||||
# Copy over next.js config
|
||||
COPY next.config.js ./next.config.js
|
||||
|
||||
# Copy all files
|
||||
COPY . .
|
||||
|
||||
|
@ -1,22 +1,50 @@
|
||||
This is the client repository for Infisical.
|
||||
# React + TypeScript + Vite
|
||||
|
||||
## Before you get started with development locally
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
|
||||
Please ensure you have Docker and Docker Compose installed for your OS.
|
||||
Currently, two official plugins are available:
|
||||
|
||||
### Steps to start server
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
|
||||
- `CD` into the repo
|
||||
- run command `docker-compose -f docker-compose.dev.yml up --build --force-recreate`
|
||||
- Visit localhost:8080 and the website should be live
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
### Steps to shutdown this Docker compose
|
||||
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
||||
|
||||
- `CD` into this repo
|
||||
- run command `docker-compose -f docker-compose.dev.yml down`
|
||||
- Configure the top-level `parserOptions` property like this:
|
||||
|
||||
### Notes
|
||||
```js
|
||||
export default tseslint.config({
|
||||
languageOptions: {
|
||||
// other options...
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Any changes made to local files in the `/components`, `/pages`, `/styles` will be hot reloaded. If would like like to watch for other files or folders live, please add them to the docker volume.
|
||||
- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
|
||||
- Optionally add `...tseslint.configs.stylisticTypeChecked`
|
||||
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
|
||||
|
||||
You will also need to ensure that a .env.local file exists with all required environment variables
|
||||
```js
|
||||
// eslint.config.js
|
||||
import react from 'eslint-plugin-react'
|
||||
|
||||
export default tseslint.config({
|
||||
// Set the react version
|
||||
settings: { react: { version: '18.3' } },
|
||||
plugins: {
|
||||
// Add the react plugin
|
||||
react,
|
||||
},
|
||||
rules: {
|
||||
// other rules...
|
||||
// Enable its recommended rules
|
||||
...react.configs.recommended.rules,
|
||||
...react.configs['jsx-runtime'].rules,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:8080',
|
||||
viewportWidth: 1480,
|
||||
viewportHeight: 920,
|
||||
},
|
||||
};
|
@ -1,47 +0,0 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
describe('organization Overview', () => {
|
||||
beforeEach(() => {
|
||||
cy.login(`test@localhost.local`, `testInfisical1`)
|
||||
})
|
||||
|
||||
const projectName = "projectY"
|
||||
|
||||
it('can`t create projects with empty names', () => {
|
||||
cy.get('.button').click()
|
||||
cy.get('input[placeholder="Type your project name"]').type('abc').clear()
|
||||
cy.intercept('*').as('anyRequest');
|
||||
cy.get('@anyRequest').should('not.exist');
|
||||
})
|
||||
|
||||
it('can delete a newly-created project', () => {
|
||||
// Create a project
|
||||
cy.get('.button').click()
|
||||
cy.get('input[placeholder="Type your project name"]').type(`${projectName}`)
|
||||
cy.contains('button', 'Create Project').click()
|
||||
cy.url().should('include', '/project')
|
||||
|
||||
// Delete a project
|
||||
cy.get(`[href^="/project/"][href$="/settings"] > a > .group`).click()
|
||||
cy.contains('button', `Delete ${projectName}`).click()
|
||||
cy.contains('button', 'Delete Project').should('have.attr', 'disabled')
|
||||
cy.get('input[placeholder="Type to delete..."]').type('confirm')
|
||||
cy.contains('button', 'Delete Project').should('not.have.attr', 'disabled')
|
||||
cy.url().then((currentUrl) => {
|
||||
let projectId = currentUrl.split("/")[4]
|
||||
cy.intercept('DELETE', `/api/v1/workspace/${projectId}`).as('deleteProject');
|
||||
cy.contains('button', 'Delete Project').click();
|
||||
cy.get('@deleteProject').should('have.property', 'response').and('have.property', 'statusCode', 200);
|
||||
})
|
||||
})
|
||||
|
||||
it('can display no projects', () => {
|
||||
cy.intercept('/api/v1/workspace', {
|
||||
body: {
|
||||
"workspaces": []
|
||||
},
|
||||
})
|
||||
cy.get('.border-mineshaft-700 > :nth-child(2)').should('have.text', 'You are not part of any projects in this organization yet. When you are, they will appear here.')
|
||||
})
|
||||
|
||||
})
|
@ -1,24 +0,0 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
describe('Organization Settings', () => {
|
||||
let orgId;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.login(`test@localhost.local`, `testInfisical1`)
|
||||
cy.url().then((currentUrl) => {
|
||||
orgId = currentUrl.split("/")[4]
|
||||
cy.visit(`org/${orgId}/settings`)
|
||||
})
|
||||
})
|
||||
|
||||
it('can rename org', () => {
|
||||
cy.get('input[placeholder="Acme Corp"]').clear().type('ABC')
|
||||
|
||||
cy.intercept('PATCH', `/api/v1/organization/${orgId}/name`).as('renameOrg');
|
||||
cy.get('form.p-4 > .button').click()
|
||||
cy.get('@renameOrg').should('have.property', 'response').and('have.property', 'statusCode', 200);
|
||||
|
||||
cy.get('.pl-3').should("have.text", "ABC ")
|
||||
})
|
||||
|
||||
})
|
@ -1,84 +0,0 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
describe('Project Overview', () => {
|
||||
const projectName = "projectY"
|
||||
let projectId;
|
||||
let isFirstTest = true;
|
||||
|
||||
before(() => {
|
||||
cy.login(`test@localhost.local`, `testInfisical1`)
|
||||
|
||||
// Create a project
|
||||
cy.get('.button').click()
|
||||
cy.get('input[placeholder="Type your project name"]').type(`${projectName}`)
|
||||
cy.contains('button', 'Create Project').click()
|
||||
cy.url().should('include', '/project').then((currentUrl) => {
|
||||
projectId = currentUrl.split("/")[4]
|
||||
})
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
if (isFirstTest) {
|
||||
isFirstTest = false;
|
||||
return; // Skip the rest of the beforeEach for the first test
|
||||
}
|
||||
cy.login(`test@localhost.local`, `testInfisical1`)
|
||||
cy.visit(`/project/${projectId}/secrets/overview`)
|
||||
})
|
||||
|
||||
it('can create secrets', () => {
|
||||
cy.contains('button', 'Go to Development').click()
|
||||
cy.contains('button', 'Add a new secret').click()
|
||||
cy.get('input[placeholder="Type your secret name"]').type('SECRET_A')
|
||||
cy.contains('button', 'Create Secret').click()
|
||||
cy.get('.w-80 > .inline-flex > .input').should('have.value', 'SECRET_A')
|
||||
cy.get(':nth-child(6) > .button > .w-min').should('have.text', '1 Commit')
|
||||
})
|
||||
|
||||
it('can update secrets', () => {
|
||||
cy.get(':nth-child(2) > .flex > .button').click()
|
||||
cy.get('.overflow-auto > .relative > .absolute').type('VALUE_A')
|
||||
cy.get('.button.text-primary > .svg-inline--fa').click()
|
||||
cy.get(':nth-child(6) > .button > .w-min').should('have.text', '2 Commits')
|
||||
})
|
||||
|
||||
it('can`t create duplicate-name secrets', () => {
|
||||
cy.get(':nth-child(2) > .flex > .button').click()
|
||||
cy.contains('button', 'Add Secret').click()
|
||||
cy.get('input[placeholder="Type your secret name"]').type('SECRET_A')
|
||||
cy.intercept('POST', `/api/v3/secrets/SECRET_A`).as('createSecret');
|
||||
cy.contains('button', 'Create Secret').click()
|
||||
cy.get('@createSecret').should('have.property', 'response').and('have.property', 'statusCode', 400);
|
||||
})
|
||||
|
||||
it('can add another secret', () => {
|
||||
cy.get(':nth-child(2) > .flex > .button').click()
|
||||
cy.contains('button', 'Add Secret').click()
|
||||
cy.get('input[placeholder="Type your secret name"]').type('SECRET_B')
|
||||
cy.contains('button', 'Create Secret').click()
|
||||
cy.get(':nth-child(6) > .button > .w-min').should('have.text', '3 Commits')
|
||||
})
|
||||
|
||||
it('can delete a secret', () => {
|
||||
cy.get(':nth-child(2) > .flex > .button').click()
|
||||
// cy.get(':nth-child(3) > .shadow-none').trigger('mouseover')
|
||||
cy.get(':nth-child(3) > .shadow-none > .group > .h-10 > .border-red').click()
|
||||
cy.contains('button', 'Delete Secret').should('have.attr', 'disabled')
|
||||
cy.get('input[placeholder="Type to delete..."]').type('SECRET_B')
|
||||
cy.intercept('DELETE', `/api/v3/secrets/SECRET_B`).as('deleteSecret');
|
||||
cy.contains('button', 'Delete Secret').should('not.have.attr', 'disabled')
|
||||
cy.contains('button', 'Delete Secret').click();
|
||||
cy.get('@deleteSecret').should('have.property', 'response').and('have.property', 'statusCode', 200);
|
||||
})
|
||||
|
||||
it('can add a comment', () => {
|
||||
return;
|
||||
cy.get(':nth-child(2) > .flex > .button').click()
|
||||
// for some reason this hover does not want to work
|
||||
cy.get('.overflow-auto').trigger('mouseover').then(() => {
|
||||
cy.get('.shadow-none > .group > .pl-4 > .h-8 > button[aria-label="add-comment"]').should('be.visible').click()
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
})
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
|
||||
Cypress.Commands.add('login', (username, password) => {
|
||||
cy.visit('/login')
|
||||
cy.get('input[placeholder="Enter your email..."]').type(username)
|
||||
cy.get('input[placeholder="Enter your password..."]').type(password)
|
||||
cy.contains('Continue with Email').click()
|
||||
cy.url().should('include', '/overview')
|
||||
})
|
||||
|
||||
// Cypress.Commands.add('login', (username, password) => {
|
||||
// cy.session([username, password], () => {
|
||||
// cy.visit('/login')
|
||||
// cy.get('input[placeholder="Enter your email..."]').type(username)
|
||||
// cy.get('input[placeholder="Enter your password..."]').type(password)
|
||||
// cy.contains('Continue with Email').click()
|
||||
// cy.url().should('include', '/overview')
|
||||
// cy.wait(2000);
|
||||
// })
|
||||
// })
|
@ -1,20 +0,0 @@
|
||||
// ***********************************************************
|
||||
// This example support/e2e.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
137
frontend/eslint.config.js
Normal file
@ -0,0 +1,137 @@
|
||||
import js from "@eslint/js";
|
||||
import globals from "globals";
|
||||
import reactHooks from "eslint-plugin-react-hooks";
|
||||
import reactRefresh from "eslint-plugin-react-refresh";
|
||||
import eslintPluginPrettier from "eslint-plugin-prettier/recommended";
|
||||
import simpleImportSort from "eslint-plugin-simple-import-sort";
|
||||
import tseslint from "typescript-eslint";
|
||||
import { FlatCompat } from "@eslint/eslintrc";
|
||||
import stylisticPlugin from "@stylistic/eslint-plugin";
|
||||
import importPlugin from "eslint-plugin-import";
|
||||
import pluginRouter from "@tanstack/eslint-plugin-router";
|
||||
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: import.meta.dirname
|
||||
});
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ["dist"] },
|
||||
{
|
||||
extends: [
|
||||
...pluginRouter.configs["flat/recommended"],
|
||||
js.configs.recommended,
|
||||
tseslint.configs.recommended,
|
||||
...compat.extends("airbnb"),
|
||||
...compat.extends("@kesills/airbnb-typescript"),
|
||||
eslintPluginPrettier
|
||||
],
|
||||
files: ["**/*.{ts,tsx}"],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
"react-hooks": reactHooks,
|
||||
"react-refresh": reactRefresh,
|
||||
"simple-import-sort": simpleImportSort,
|
||||
import: importPlugin
|
||||
},
|
||||
settings: {
|
||||
"import/resolver": {
|
||||
typescript: {
|
||||
project: ["./tsconfig.json"]
|
||||
}
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
"react-refresh/only-export-components": "off",
|
||||
"@typescript-eslint/only-throw-error": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
quotes: ["error", "double", { avoidEscape: true }],
|
||||
"comma-dangle": ["error", "only-multiline"],
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"import/prefer-default-export": "off",
|
||||
"react-hooks/exhaustive-deps": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "warn",
|
||||
"react/jsx-props-no-spreading": "off", // switched off for component building
|
||||
// TODO: This rule will be switched ON after complete revamp of frontend
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"jsx-a11y/control-has-associated-label": "off",
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
devDependencies: true
|
||||
}
|
||||
],
|
||||
"no-console": "off",
|
||||
"arrow-body-style": "off",
|
||||
"no-underscore-dangle": [
|
||||
"error",
|
||||
{
|
||||
allow: ["_id"]
|
||||
}
|
||||
],
|
||||
"jsx-a11y/anchor-is-valid": "off",
|
||||
// all those <a> tags must be converted to label or a p component
|
||||
//
|
||||
"react/require-default-props": "off",
|
||||
"react/jsx-filename-extension": [
|
||||
1,
|
||||
{
|
||||
extensions: [".tsx", ".ts"]
|
||||
}
|
||||
],
|
||||
// TODO: turn this rule ON after migration. everything should use arrow functions
|
||||
"react/function-component-definition": [
|
||||
0,
|
||||
{
|
||||
namedComponents: "arrow-function"
|
||||
}
|
||||
],
|
||||
"react/no-unknown-property": [
|
||||
"error",
|
||||
{
|
||||
ignore: ["jsx"]
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"simple-import-sort/exports": "warn",
|
||||
"simple-import-sort/imports": [
|
||||
"warn",
|
||||
{
|
||||
groups: [
|
||||
// Node.js builtins. You could also generate this regex if you use a `.js` config.
|
||||
// For example: `^(${require("module").builtinModules.join("|")})(/|$)`
|
||||
// Note that if you use the `node:` prefix for Node.js builtins,
|
||||
// you can avoid this complexity: You can simply use "^node:".
|
||||
[
|
||||
"^(assert|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|https|module|net|os|path|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|tty|url|util|vm|zlib|freelist|v8|process|async_hooks|http2|perf_hooks)(/.*|$)"
|
||||
],
|
||||
// Packages `react` related packages
|
||||
["^react", "^next", "^@?\\w"],
|
||||
["^@app"],
|
||||
// Internal packages.
|
||||
["^~(/.*|$)"],
|
||||
// Relative imports
|
||||
["^\\.\\.(?!/?$)", "^\\.\\./?$", "^\\./(?=.*/)(?!/?$)", "^\\.(?!/?$)", "^\\./?$"],
|
||||
// Style imports.
|
||||
["^.+\\.?(css|scss)$"]
|
||||
]
|
||||
}
|
||||
],
|
||||
"import/first": "error",
|
||||
"import/newline-after-import": "error",
|
||||
"import/no-duplicates": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
rules: Object.fromEntries(
|
||||
Object.keys(stylisticPlugin.configs["all-flat"].rules ?? {}).map((key) => [key, "off"])
|
||||
)
|
||||
}
|
||||
);
|
29
frontend/index.html
Normal file
@ -0,0 +1,29 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="
|
||||
default-src 'self';
|
||||
connect-src 'self' https://*.posthog.com http://127.0.0.1:* https://cdn.jsdelivr.net/npm/@lottiefiles/dotlottie-web@0.38.2/dist/dotlottie-player.wasm;
|
||||
script-src 'self' https://*.posthog.com https://js.stripe.com https://api.stripe.com https://widget.intercom.io https://js.intercomcdn.com https://hcaptcha.com https://*.hcaptcha.com 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net/npm/@lottiefiles/dotlottie-web@0.38.2/dist/dotlottie-player.wasm;
|
||||
style-src 'self' 'unsafe-inline' https://hcaptcha.com https://*.hcaptcha.com;
|
||||
child-src https://api.stripe.com;
|
||||
frame-src https://js.stripe.com/ https://api.stripe.com https://www.youtube.com/ https://hcaptcha.com https://*.hcaptcha.com;
|
||||
connect-src 'self' wss://nexus-websocket-a.intercom.io https://api-iam.intercom.io https://api.heroku.com/ https://id.heroku.com/oauth/authorize https://id.heroku.com/oauth/token https://checkout.stripe.com https://app.posthog.com https://api.stripe.com https://api.pwnedpasswords.com http://127.0.0.1:* https://hcaptcha.com https://*.hcaptcha.com;
|
||||
img-src 'self' https://static.intercomassets.com https://js.intercomcdn.com https://downloads.intercomcdn.com https://*.stripe.com https://i.ytimg.com/ data:;
|
||||
media-src https://js.intercomcdn.com;
|
||||
font-src 'self' https://fonts.intercomcdn.com/ https://fonts.gstatic.com;
|
||||
"
|
||||
/>
|
||||
<title>Infisical</title>
|
||||
<script src="/runtime-ui-env.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
5
frontend/next-env.d.ts
vendored
@ -1,5 +0,0 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
@ -1,98 +0,0 @@
|
||||
const path = require("path");
|
||||
|
||||
const ContentSecurityPolicy = `
|
||||
default-src 'self';
|
||||
connect-src 'self' https://*.posthog.com http://127.0.0.1:*;
|
||||
script-src 'self' https://*.posthog.com https://js.stripe.com https://api.stripe.com https://widget.intercom.io https://js.intercomcdn.com https://hcaptcha.com https://*.hcaptcha.com 'unsafe-inline' 'unsafe-eval';
|
||||
style-src 'self' https://rsms.me 'unsafe-inline' https://hcaptcha.com https://*.hcaptcha.com;
|
||||
child-src https://api.stripe.com;
|
||||
frame-src https://js.stripe.com/ https://api.stripe.com https://www.youtube.com/ https://hcaptcha.com https://*.hcaptcha.com;
|
||||
connect-src 'self' wss://nexus-websocket-a.intercom.io https://api-iam.intercom.io https://api.heroku.com/ https://id.heroku.com/oauth/authorize https://id.heroku.com/oauth/token https://checkout.stripe.com https://app.posthog.com https://api.stripe.com https://api.pwnedpasswords.com http://127.0.0.1:* https://hcaptcha.com https://*.hcaptcha.com;
|
||||
img-src 'self' https://static.intercomassets.com https://js.intercomcdn.com https://downloads.intercomcdn.com https://*.stripe.com https://i.ytimg.com/ data:;
|
||||
media-src https://js.intercomcdn.com;
|
||||
font-src 'self' https://fonts.intercomcdn.com/ https://maxcdn.bootstrapcdn.com https://rsms.me https://fonts.gstatic.com;
|
||||
`;
|
||||
|
||||
// You can choose which headers to add to the list
|
||||
// after learning more below.
|
||||
const securityHeaders = [
|
||||
{
|
||||
key: "X-DNS-Prefetch-Control",
|
||||
value: "on"
|
||||
},
|
||||
{
|
||||
key: "Strict-Transport-Security",
|
||||
value: "max-age=63072000; includeSubDomains; preload"
|
||||
},
|
||||
{
|
||||
key: "X-XSS-Protection",
|
||||
value: "1; mode=block"
|
||||
},
|
||||
{
|
||||
key: "X-Frame-Options",
|
||||
value: "SAMEORIGIN"
|
||||
},
|
||||
{
|
||||
key: "Permissions-Policy",
|
||||
value: "camera=(), microphone=()"
|
||||
},
|
||||
{
|
||||
key: "X-Content-Type-Options",
|
||||
value: "nosniff"
|
||||
},
|
||||
{
|
||||
key: "Referrer-Policy",
|
||||
value: "strict-origin-when-cross-origin"
|
||||
},
|
||||
{
|
||||
key: "Content-Security-Policy",
|
||||
value: ContentSecurityPolicy.replace(/\s{2,}/g, " ").trim()
|
||||
}
|
||||
];
|
||||
/**
|
||||
* @type {import('next').NextConfig}
|
||||
**/
|
||||
module.exports = {
|
||||
output: "standalone",
|
||||
i18n: {
|
||||
locales: ["en", "ko", "fr", "pt-BR", "pt-PT", "es"],
|
||||
defaultLocale: "en"
|
||||
},
|
||||
async headers() {
|
||||
return [
|
||||
{
|
||||
// Apply these headers to all routes in your application.
|
||||
source: "/:path*",
|
||||
headers: securityHeaders
|
||||
}
|
||||
];
|
||||
},
|
||||
webpack: (config, { isServer, webpack }) => {
|
||||
// config
|
||||
config.module.rules.push({
|
||||
test: /\.wasm$/,
|
||||
loader: "base64-loader",
|
||||
type: "javascript/auto"
|
||||
});
|
||||
|
||||
config.module.noParse = /\.wasm$/;
|
||||
|
||||
config.module.rules.forEach((rule) => {
|
||||
(rule.oneOf || []).forEach((oneOf) => {
|
||||
if (oneOf.loader && oneOf.loader.indexOf("file-loader") >= 0) {
|
||||
oneOf.exclude.push(/\.wasm$/);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!isServer) {
|
||||
config.resolve.fallback.fs = false;
|
||||
}
|
||||
|
||||
// Perform customizations to webpack config
|
||||
config.plugins.push(new webpack.IgnorePlugin({ resourceRegExp: /\/__tests__\// }));
|
||||
|
||||
// Important: return the modified config
|
||||
return config;
|
||||
}
|
||||
};
|
23584
frontend/package-lock.json
generated
@ -1,165 +1,134 @@
|
||||
{
|
||||
"name": "frontend-v2",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"prepare": "cd .. && npm install",
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"start:docker": "next build && next start",
|
||||
"lint": "eslint --ext js,ts,tsx ./src",
|
||||
"lint:fix": "eslint --fix --ext js,ts,tsx ./src",
|
||||
"type:check": "tsc --project tsconfig.json --noEmit",
|
||||
"storybook": "storybook dev -p 6006 -s ./public",
|
||||
"build-storybook": "storybook build"
|
||||
},
|
||||
"overrides": {
|
||||
"@storybook/nextjs": {
|
||||
"sharp": "npm:dry-uninstall"
|
||||
}
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint ./src",
|
||||
"lint:fix": "eslint --fix ./src",
|
||||
"type:check": "tsc --noEmit --project ./tsconfig.app.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@casl/ability": "^6.5.0",
|
||||
"@casl/react": "^3.1.0",
|
||||
"@dnd-kit/core": "^6.0.8",
|
||||
"@dnd-kit/modifiers": "^6.0.1",
|
||||
"@dnd-kit/sortable": "^7.0.2",
|
||||
"@emotion/css": "^11.10.0",
|
||||
"@emotion/server": "^11.10.0",
|
||||
"@fontsource/inter": "^4.5.15",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.1.2",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.1.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.1.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.1.2",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@hcaptcha/react-hcaptcha": "^1.10.1",
|
||||
"@headlessui/react": "^1.7.7",
|
||||
"@hookform/resolvers": "^2.9.10",
|
||||
"@octokit/rest": "^19.0.7",
|
||||
"@peculiar/x509": "^1.11.0",
|
||||
"@radix-ui/react-accordion": "^1.1.2",
|
||||
"@radix-ui/react-alert-dialog": "^1.0.5",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-collapsible": "^1.0.3",
|
||||
"@radix-ui/react-dialog": "^1.0.5",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
||||
"@radix-ui/react-hover-card": "^1.0.7",
|
||||
"@radix-ui/react-label": "^2.0.2",
|
||||
"@radix-ui/react-popover": "^1.0.7",
|
||||
"@radix-ui/react-popper": "^1.1.3",
|
||||
"@radix-ui/react-progress": "^1.0.3",
|
||||
"@radix-ui/react-radio-group": "^1.1.3",
|
||||
"@radix-ui/react-select": "^2.0.0",
|
||||
"@radix-ui/react-switch": "^1.0.3",
|
||||
"@radix-ui/react-tabs": "^1.0.4",
|
||||
"@radix-ui/react-toast": "^1.1.5",
|
||||
"@radix-ui/react-tooltip": "^1.0.7",
|
||||
"@reduxjs/toolkit": "^1.8.3",
|
||||
"@sindresorhus/slugify": "1.1.0",
|
||||
"@stripe/react-stripe-js": "^1.16.3",
|
||||
"@stripe/stripe-js": "^1.46.0",
|
||||
"@tanstack/react-query": "^4.23.0",
|
||||
"@types/argon2-browser": "^1.18.1",
|
||||
"@casl/ability": "^6.7.2",
|
||||
"@casl/react": "^4.0.0",
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/modifiers": "^9.0.0",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@fontsource/inter": "^5.1.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.7.1",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.7.1",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.7.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.7.1",
|
||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||
"@hcaptcha/react-hcaptcha": "^1.11.0",
|
||||
"@headlessui/react": "^1.7.19",
|
||||
"@hookform/resolvers": "^3.9.1",
|
||||
"@lottiefiles/dotlottie-react": "^0.12.0",
|
||||
"@octokit/rest": "^21.0.2",
|
||||
"@peculiar/x509": "^1.12.3",
|
||||
"@radix-ui/react-accordion": "^1.2.2",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.3",
|
||||
"@radix-ui/react-checkbox": "^1.1.3",
|
||||
"@radix-ui/react-collapsible": "^1.1.2",
|
||||
"@radix-ui/react-dialog": "^1.1.3",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.3",
|
||||
"@radix-ui/react-hover-card": "^1.1.3",
|
||||
"@radix-ui/react-label": "^2.1.1",
|
||||
"@radix-ui/react-popover": "^1.1.3",
|
||||
"@radix-ui/react-popper": "^1.2.1",
|
||||
"@radix-ui/react-progress": "^1.1.1",
|
||||
"@radix-ui/react-radio-group": "^1.2.2",
|
||||
"@radix-ui/react-select": "^2.1.3",
|
||||
"@radix-ui/react-switch": "^1.1.2",
|
||||
"@radix-ui/react-tabs": "^1.1.2",
|
||||
"@radix-ui/react-toast": "^1.2.3",
|
||||
"@radix-ui/react-tooltip": "^1.1.5",
|
||||
"@sindresorhus/slugify": "^2.2.1",
|
||||
"@tanstack/react-query": "^5.62.7",
|
||||
"@tanstack/react-router": "^1.95.1",
|
||||
"@tanstack/virtual-file-routes": "^1.87.6",
|
||||
"@tanstack/zod-adapter": "^1.91.0",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@ucast/mongo2js": "^1.3.4",
|
||||
"add": "^2.0.6",
|
||||
"argon2-browser": "^1.18.0",
|
||||
"axios": "^0.28.0",
|
||||
"axios-auth-refresh": "^3.3.6",
|
||||
"base64-loader": "^1.0.0",
|
||||
"classnames": "^2.3.1",
|
||||
"cookies": "^0.9.1",
|
||||
"cva": "npm:class-variance-authority@^0.4.0",
|
||||
"date-fns": "^2.30.0",
|
||||
"axios": "^1.7.9",
|
||||
"classnames": "^2.5.1",
|
||||
"cva": "npm:class-variance-authority@^0.7.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"framer-motion": "^6.2.3",
|
||||
"fs": "^0.0.2",
|
||||
"gray-matter": "^4.0.3",
|
||||
"http-proxy": "^1.18.1",
|
||||
"i18next": "^22.4.15",
|
||||
"i18next-browser-languagedetector": "^7.0.1",
|
||||
"i18next-http-backend": "^2.2.0",
|
||||
"infisical-node": "^1.0.37",
|
||||
"framer-motion": "^11.14.1",
|
||||
"i18next": "^24.1.0",
|
||||
"i18next-browser-languagedetector": "^8.0.2",
|
||||
"i18next-http-backend": "^3.0.1",
|
||||
"jspdf": "^2.5.2",
|
||||
"jsrp": "^0.2.4",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"lottie-react": "^2.4.0",
|
||||
"markdown-it": "^13.0.1",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"ms": "^2.1.3",
|
||||
"next": "^12.3.4",
|
||||
"nprogress": "^0.2.0",
|
||||
"picomatch": "^2.3.1",
|
||||
"posthog-js": "^1.105.6",
|
||||
"picomatch": "^4.0.2",
|
||||
"posthog-js": "^1.198.0",
|
||||
"qrcode": "^1.5.4",
|
||||
"query-string": "^7.1.3",
|
||||
"react": "^17.0.2",
|
||||
"react-beautiful-dnd": "^13.1.1",
|
||||
"react": "^18.3.1",
|
||||
"react-code-input": "^3.10.1",
|
||||
"react-day-picker": "^8.8.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-grid-layout": "^1.3.4",
|
||||
"react-hook-form": "^7.43.0",
|
||||
"react-i18next": "^12.2.2",
|
||||
"react-icons": "^5.3.0",
|
||||
"react-mailchimp-subscribe": "^2.1.3",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-redux": "^8.0.2",
|
||||
"react-select": "^5.8.1",
|
||||
"react-table": "^7.8.0",
|
||||
"react-toastify": "^9.1.3",
|
||||
"sanitize-html": "^2.12.1",
|
||||
"set-cookie-parser": "^2.5.1",
|
||||
"sharp": "^0.33.2",
|
||||
"styled-components": "^5.3.7",
|
||||
"tailwind-merge": "^1.8.1",
|
||||
"react-day-picker": "^9.4.3",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-hook-form": "^7.54.0",
|
||||
"react-i18next": "^15.2.0",
|
||||
"react-icons": "^5.4.0",
|
||||
"react-select": "^5.9.0",
|
||||
"react-toastify": "^10.0.6",
|
||||
"redaxios": "^0.5.1",
|
||||
"tailwind-merge": "^2.5.5",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"tweetnacl-util": "^0.15.1",
|
||||
"uuid": "^8.3.2",
|
||||
"uuidv4": "^6.2.13",
|
||||
"yaml": "^2.2.2",
|
||||
"yup": "^0.32.11",
|
||||
"zod": "^3.22.3",
|
||||
"zustand": "^4.5.0"
|
||||
"yaml": "^2.6.1",
|
||||
"zod": "^3.24.1",
|
||||
"zustand": "^5.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/addon-essentials": "^7.5.2",
|
||||
"@storybook/addon-interactions": "^7.0.23",
|
||||
"@storybook/addon-links": "^7.0.23",
|
||||
"@storybook/addon-styling": "^1.3.0",
|
||||
"@storybook/blocks": "^7.0.23",
|
||||
"@storybook/client-api": "^7.2.1",
|
||||
"@storybook/nextjs": "^7.0.23",
|
||||
"@storybook/react": "^7.0.23",
|
||||
"@storybook/testing-library": "^0.2.0",
|
||||
"@tailwindcss/typography": "^0.5.4",
|
||||
"@types/file-saver": "^2.0.5",
|
||||
"@types/jsrp": "^0.2.4",
|
||||
"@types/node": "^18.11.9",
|
||||
"@types/picomatch": "^2.3.0",
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"@eslint/js": "^9.15.0",
|
||||
"@kesills/eslint-config-airbnb-typescript": "^20.0.0",
|
||||
"@stylistic/eslint-plugin": "^2.12.1",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@tanstack/eslint-plugin-router": "^1.87.6",
|
||||
"@tanstack/router-devtools": "^1.87.9",
|
||||
"@tanstack/router-plugin": "^1.95.1",
|
||||
"@types/argon2-browser": "^1.18.4",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/jsrp": "^0.2.6",
|
||||
"@types/ms": "^0.7.34",
|
||||
"@types/picomatch": "^3.0.1",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/sanitize-html": "^2.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.1",
|
||||
"@typescript-eslint/parser": "^5.45.0",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"cypress": "^13.3.2",
|
||||
"eslint": "^8.32.0",
|
||||
"@types/react": "^18.3.12",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@types/react-helmet": "^6.1.11",
|
||||
"@vitejs/plugin-react-swc": "^3.5.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-airbnb-typescript": "^17.0.0",
|
||||
"eslint-config-next": "^13.0.5",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-import-resolver-typescript": "^3.5.2",
|
||||
"eslint-plugin-import": "^2.27.4",
|
||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.32.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-simple-import-sort": "^8.0.0",
|
||||
"eslint-plugin-storybook": "^0.6.12",
|
||||
"postcss": "^8.4.39",
|
||||
"prettier": "^2.8.3",
|
||||
"prettier-plugin-tailwindcss": "^0.2.2",
|
||||
"storybook": "^7.6.20",
|
||||
"storybook-dark-mode": "^3.0.0",
|
||||
"tailwindcss": "3.2",
|
||||
"typescript": "^4.9.3"
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-import-resolver-typescript": "^3.7.0",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-react-refresh": "^0.4.14",
|
||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||
"globals": "^15.12.0",
|
||||
"postcss": "^8.4.49",
|
||||
"prettier": "3.4.2",
|
||||
"prettier-plugin-tailwindcss": "^0.6.9",
|
||||
"tailwindcss": "^3.4.16",
|
||||
"typescript": "~5.6.2",
|
||||
"typescript-eslint": "^8.15.0",
|
||||
"vite": "^5.4.11",
|
||||
"vite-plugin-node-polyfills": "^0.22.0",
|
||||
"vite-plugin-top-level-await": "^1.4.4",
|
||||
"vite-plugin-wasm": "^3.3.0",
|
||||
"vite-tsconfig-paths": "^5.1.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
module.exports = {
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -1,94 +0,0 @@
|
||||
interface Mapping {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
const integrationSlugNameMapping: Mapping = {
|
||||
"azure-key-vault": "Azure Key Vault",
|
||||
"aws-parameter-store": "AWS Parameter Store",
|
||||
"aws-secret-manager": "AWS Secrets Manager",
|
||||
heroku: "Heroku",
|
||||
vercel: "Vercel",
|
||||
netlify: "Netlify",
|
||||
github: "GitHub",
|
||||
gitlab: "GitLab",
|
||||
render: "Render",
|
||||
"laravel-forge": "Laravel Forge",
|
||||
railway: "Railway",
|
||||
flyio: "Fly.io",
|
||||
circleci: "CircleCI",
|
||||
databricks: "Databricks",
|
||||
travisci: "TravisCI",
|
||||
supabase: "Supabase",
|
||||
checkly: "Checkly",
|
||||
qovery: "Qovery",
|
||||
"terraform-cloud": "Terraform Cloud",
|
||||
teamcity: "TeamCity",
|
||||
"hashicorp-vault": "Vault",
|
||||
"cloudflare-pages": "Cloudflare Pages",
|
||||
"cloudflare-workers": "Cloudflare Workers",
|
||||
codefresh: "Codefresh",
|
||||
"digital-ocean-app-platform": "Digital Ocean App Platform",
|
||||
bitbucket: "Bitbucket",
|
||||
"cloud-66": "Cloud 66",
|
||||
northflank: "Northflank",
|
||||
windmill: "Windmill",
|
||||
"gcp-secret-manager": "GCP Secret Manager",
|
||||
"hasura-cloud": "Hasura Cloud",
|
||||
rundeck: "Rundeck",
|
||||
"azure-devops": "Azure DevOps",
|
||||
"azure-app-configuration": "Azure App Configuration",
|
||||
"octopus-deploy": "Octopus Deploy"
|
||||
};
|
||||
|
||||
const envMapping: Mapping = {
|
||||
Development: "dev",
|
||||
Staging: "staging",
|
||||
Production: "prod",
|
||||
Testing: "test"
|
||||
};
|
||||
|
||||
const reverseEnvMapping: Mapping = {
|
||||
dev: "Development",
|
||||
staging: "Staging",
|
||||
prod: "Production",
|
||||
test: "Testing"
|
||||
};
|
||||
|
||||
const contextNetlifyMapping: Mapping = {
|
||||
dev: "Local development",
|
||||
"branch-deploy": "Branch deploys",
|
||||
"deploy-preview": "Deploy Previews",
|
||||
production: "Production"
|
||||
};
|
||||
|
||||
const reverseContextNetlifyMapping: Mapping = {
|
||||
"Local development": "dev",
|
||||
"Branch deploys": "branch-deploy",
|
||||
"Deploy Previews": "deploy-preview",
|
||||
Production: "production"
|
||||
};
|
||||
|
||||
const plansDev: Mapping = {
|
||||
starter: "prod_Mb4ATFT5QAHoPM",
|
||||
team: "prod_NEpD2WMXUS2eDn",
|
||||
professional: "prod_Mb4CetZ2jE7jdl",
|
||||
enterprise: "licence_key_required"
|
||||
};
|
||||
|
||||
const plansProd: Mapping = {
|
||||
starter: "prod_Mb8oR5XNwyFTul",
|
||||
team: "prod_NEp7fAB3UJWK6A",
|
||||
professional: "prod_Mb8pUIpA0OUi5N",
|
||||
enterprise: "licence_key_required"
|
||||
};
|
||||
|
||||
const plans = plansProd || plansDev;
|
||||
|
||||
export {
|
||||
contextNetlifyMapping,
|
||||
envMapping,
|
||||
integrationSlugNameMapping,
|
||||
plans,
|
||||
reverseContextNetlifyMapping,
|
||||
reverseEnvMapping
|
||||
};
|
@ -1,19 +0,0 @@
|
||||
export interface Tag {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
user: string;
|
||||
workspace: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface SecretDataProps {
|
||||
pos: number;
|
||||
key: string;
|
||||
value: string | undefined;
|
||||
valueOverride: string | undefined;
|
||||
id: string;
|
||||
idOverride?: string;
|
||||
comment: string;
|
||||
tags: Tag[];
|
||||
}
|
1
frontend/public/lotties/circular-check.json
Normal file
1
frontend/public/lotties/groups.json
Normal file
1
frontend/public/lotties/jigsaw-puzzle.json
Normal file
1
frontend/public/lotties/lock-closed.json
Normal file
1
frontend/public/lotties/moving-block.json
Normal file
1
frontend/public/lotties/secret-scan.json
Normal file
1
frontend/public/lotties/sliding-carousel.json
Normal file
1
frontend/public/lotties/spinning-coin.json
Normal file
1
frontend/public/lotties/toggle-settings.json
Normal file
1
frontend/public/lotties/verified.json
Normal file
@ -1,4 +0,0 @@
|
||||
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
1
frontend/public/vite.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
@ -6,6 +6,8 @@ scripts/replace-standalone-build-variable.sh "$BAKED_NEXT_PUBLIC_INTERCOM_ID" "$
|
||||
|
||||
scripts/replace-standalone-build-variable.sh "$BAKED_NEXT_PUBLIC_CAPTCHA_SITE_KEY" "$NEXT_PUBLIC_CAPTCHA_SITE_KEY"
|
||||
|
||||
scripts/set-frontend-config.sh
|
||||
|
||||
if [ "$TELEMETRY_ENABLED" != "false" ]; then
|
||||
echo "Telemetry is enabled"
|
||||
scripts/set-standalone-build-telemetry.sh true
|
||||
|
@ -10,7 +10,7 @@ fi
|
||||
|
||||
echo "Replacing pre-baked value.."
|
||||
|
||||
find public .next -type f -name "*.js" |
|
||||
find assets -type f -name "*.js" |
|
||||
while read file; do
|
||||
sed -i "s|$ORIGINAL|$REPLACEMENT|g" "$file"
|
||||
done
|
||||
|
9
frontend/scripts/set-frontend-config.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Configuration output file
|
||||
CONFIG_FILE="runtime-config.js"
|
||||
|
||||
# Replace content in the config file with SENTRY_DSN interpolation
|
||||
echo "window.__CONFIG__ = Object.freeze({ CAPTCHA_SITE_KEY: \"${CAPTCHA_SITE_KEY}\", CAPTCHA_SITE_KEY: \"${CAPTCHA_SITE_KEY}\", CAPTCHA_SITE_KEY: \"${CAPTCHA_SITE_KEY}\" })" > $CONFIG_FILE
|
||||
|
||||
echo "Configuration file updated at $CONFIG_FILE"
|
@ -1,92 +0,0 @@
|
||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { Button, Checkbox, PopoverContent } from "@app/components/v2";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
||||
|
||||
import { WsTag } from "../../hooks/api/tags/types";
|
||||
import { ProjectPermissionCan } from "../permissions";
|
||||
|
||||
interface Props {
|
||||
wsTags: WsTag[] | undefined;
|
||||
secKey: string;
|
||||
selectedTagIds: Record<string, boolean>;
|
||||
handleSelectTag: (wsTag: WsTag) => void;
|
||||
handleTagOnMouseEnter: (wsTag: WsTag) => void;
|
||||
handleTagOnMouseLeave: () => void;
|
||||
checkIfTagIsVisible: (wsTag: WsTag) => boolean;
|
||||
handleOnCreateTagOpen: () => void;
|
||||
}
|
||||
|
||||
const AddTagPopoverContent = ({
|
||||
wsTags,
|
||||
secKey,
|
||||
selectedTagIds,
|
||||
handleSelectTag,
|
||||
handleTagOnMouseEnter,
|
||||
handleTagOnMouseLeave,
|
||||
checkIfTagIsVisible,
|
||||
handleOnCreateTagOpen
|
||||
}: Props) => {
|
||||
return (
|
||||
<PopoverContent
|
||||
side="left"
|
||||
className="relative max-h-96 w-auto min-w-[200px] overflow-y-auto overflow-x-hidden border border-mineshaft-600 bg-mineshaft-800 p-2 text-bunker-200"
|
||||
hideCloseBtn
|
||||
>
|
||||
<div className=" text-center text-sm font-medium text-bunker-200">
|
||||
Add tags to {secKey || "this secret"}
|
||||
</div>
|
||||
<div className="absolute left-0 mt-2 w-full border-t border-mineshaft-600" />
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
{wsTags?.map((wsTag: WsTag) => (
|
||||
<div
|
||||
key={`tag-${wsTag.id}`}
|
||||
className="relative mt-4 flex h-[32px] items-center justify-start rounded-md bg-none p-2 hover:border hover:border-mineshaft-600 hover:bg-mineshaft-700 hover:text-bunker-200"
|
||||
onClick={() => handleSelectTag(wsTag)}
|
||||
onMouseEnter={() => handleTagOnMouseEnter(wsTag)}
|
||||
onMouseLeave={() => handleTagOnMouseLeave()}
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
onKeyDown={() => {}}
|
||||
>
|
||||
{(checkIfTagIsVisible(wsTag) || selectedTagIds?.[wsTag.slug]) && (
|
||||
<Checkbox
|
||||
id="autoCapitalization"
|
||||
isChecked={selectedTagIds?.[wsTag.slug]}
|
||||
className="absolute top-[50%] left-[10px] translate-y-[-50%] "
|
||||
checkIndicatorBg={`${
|
||||
!selectedTagIds?.[wsTag.slug] ? "text-transparent" : "text-mineshaft-800"
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
<div className="ml-7 flex items-center gap-3">
|
||||
<div
|
||||
className="h-[10px] w-[10px] rounded-full"
|
||||
style={{ background: wsTag?.color ? wsTag.color : "#bec2c8" }}
|
||||
>
|
||||
{" "}
|
||||
</div>
|
||||
<span>{wsTag.slug}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<ProjectPermissionCan I={ProjectPermissionActions.Create} a={ProjectPermissionSub.Tags}>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
onClick={() => handleOnCreateTagOpen()}
|
||||
isDisabled={!isAllowed}
|
||||
size="xs"
|
||||
className="mt-2"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} className="ml-1 mr-2" />}
|
||||
>
|
||||
Add new tag
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddTagPopoverContent;
|
@ -1,72 +0,0 @@
|
||||
import { ReactNode, useEffect, useState } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import { publicPaths } from "@app/const";
|
||||
import checkAuth from "@app/pages/api/auth/CheckAuth";
|
||||
|
||||
// #TODO: finish spinner only when the data loads fully
|
||||
// #TODO: Redirect somewhere if the page does not exist
|
||||
|
||||
type Prop = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export default function RouteGuard({ children }: Prop): JSX.Element {
|
||||
const router = useRouter();
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [authorized, setAuthorized] = useState(false);
|
||||
|
||||
/**
|
||||
* redirect to login page if accessing a private page and not logged in
|
||||
*/
|
||||
async function authCheck(url: string) {
|
||||
// Make sure that we don't redirect when the user is on the following pages.
|
||||
const path = `/${url.split("?")[0].split("/")[1]}`;
|
||||
|
||||
// Check if the user is authenticated
|
||||
const response = await checkAuth();
|
||||
// #TODO: figure our why sometimes it doesn't output a response
|
||||
// ANS(akhilmhdh): Because inside the security client the await token() doesn't have try/catch
|
||||
if (!publicPaths.includes(path)) {
|
||||
try {
|
||||
if (response.status !== 200) {
|
||||
router.push("/login");
|
||||
console.log("Unauthorized to access.");
|
||||
setAuthorized(false);
|
||||
} else {
|
||||
setAuthorized(true);
|
||||
console.log("Authorized to access.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Error (probably the authCheck route is stuck again...):", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// on initial load - run auth check
|
||||
(async () => {
|
||||
await authCheck(router.asPath);
|
||||
})();
|
||||
|
||||
// on route change start - hide page content by setting authorized to false
|
||||
// #TODO: add the loading page when not yet authorized.
|
||||
const hideContent = () => setAuthorized(false);
|
||||
// const onError = () => setAuthorized(true)
|
||||
router.events.on("routeChangeStart", hideContent);
|
||||
// router.events.on("routeChangeError", onError);
|
||||
|
||||
// on route change complete - run auth check
|
||||
router.events.on("routeChangeComplete", authCheck);
|
||||
|
||||
// unsubscribe from events in useEffect return function
|
||||
return () => {
|
||||
router.events.off("routeChangeStart", hideContent);
|
||||
router.events.off("routeChangeComplete", authCheck);
|
||||
// router.events.off("routeChangeError", onError);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return children as JSX.Element;
|
||||
}
|
@ -1,18 +1,18 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/* eslint-disable no-undef */
|
||||
import posthog from "posthog-js";
|
||||
|
||||
import { ENV, POSTHOG_API_KEY, POSTHOG_HOST } from "../utilities/config";
|
||||
import { envConfig } from "@app/config/env";
|
||||
|
||||
export const initPostHog = () => {
|
||||
// @ts-ignore
|
||||
console.log("Hi there 👋");
|
||||
try {
|
||||
if (typeof window !== "undefined") {
|
||||
// @ts-ignore
|
||||
if (ENV === "production" && TELEMETRY_CAPTURING_ENABLED === true) {
|
||||
posthog.init(POSTHOG_API_KEY, {
|
||||
api_host: POSTHOG_HOST
|
||||
if (
|
||||
envConfig.ENV === "production" &&
|
||||
envConfig.TELEMETRY_CAPTURING_ENABLED === true &&
|
||||
envConfig.POSTHOG_API_KEY
|
||||
) {
|
||||
posthog.init(envConfig.POSTHOG_API_KEY, {
|
||||
api_host: envConfig.POSTHOG_HOST
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* eslint-disable react/jsx-props-no-spreading */
|
||||
import React, { useState } from "react";
|
||||
import { useState } from "react";
|
||||
import ReactCodeInput from "react-code-input";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
@ -97,7 +97,7 @@ export default function CodeInputStep({
|
||||
fields={6}
|
||||
onChange={setCode}
|
||||
{...props}
|
||||
className="mt-6 mb-2"
|
||||
className="mb-2 mt-6"
|
||||
/>
|
||||
</div>
|
||||
<div className="mx-auto mt-4 block w-max md:hidden">
|
||||
@ -108,7 +108,7 @@ export default function CodeInputStep({
|
||||
fields={6}
|
||||
onChange={setCode}
|
||||
{...propsPhone}
|
||||
className="mt-2 mb-2"
|
||||
className="mb-2 mt-2"
|
||||
/>
|
||||
</div>
|
||||
{codeError && <Error text={t("signup.step2-code-error")} />}
|