mirror of
https://github.com/Infisical/infisical.git
synced 2025-03-24 00:15:26 +00:00
Compare commits
53 Commits
infisical-
...
snyk-fix-4
Author | SHA1 | Date | |
---|---|---|---|
9ed2bb38c3 | |||
f458cf0d40 | |||
ce3dc86f78 | |||
d1927cb9cf | |||
e80426f72e | |||
f5cd68168b | |||
1a0a9a7402 | |||
afdc5e8531 | |||
57daeb71e6 | |||
98b5f713a5 | |||
1855fc769d | |||
217fef65e8 | |||
8a0fd62785 | |||
c69601c14e | |||
faf6323a58 | |||
b82d1b6a5d | |||
3dcda44c50 | |||
f320b08ca8 | |||
df6e5674cf | |||
6bac143a8e | |||
38b93e499f | |||
a521538010 | |||
8cc2553452 | |||
b1cb9de001 | |||
036256b350 | |||
d3a06b82e6 | |||
87436cfb57 | |||
5c58a4d1a3 | |||
03a91b2c59 | |||
751361bd54 | |||
b4b88daf36 | |||
6546740bd9 | |||
b32558c66f | |||
effd30857e | |||
60998c8944 | |||
3c4d9fd4a9 | |||
ad70c783e8 | |||
7347362738 | |||
4b7f2e808b | |||
57f9d13189 | |||
79694750af | |||
03db367a4e | |||
b0fb848a92 | |||
4fdfcd50dc | |||
db205b855a | |||
e707f0d235 | |||
48a97fb39d | |||
d8ea26feb7 | |||
dc146d0883 | |||
24dd79b566 | |||
00650df501 | |||
9fe2021d9f | |||
fe2f2f972e |
.env.example.env.migration.example
.github/workflows
.gitignoreMakefileREADME.mdbackend
package-lock.jsonpackage.json
docker-compose.dev.ymldocker-compose.pg.ymldocker-compose.prod.ymlscripts
src
db
ee
routes/v1
services/saml-config
server
plugins
routes
v1
admin-router.tsidentity-access-token-router.tsidentity-router.tsidentity-ua.tsproject-env-router.tsproject-membership-router.tssecret-folder-router.tssecret-import-router.ts
v2
identity-org-router.tsidentity-project-router.tsorganization-router.tsproject-router.tsservice-token-router.tsuser-router.ts
v3
services
auth
identity-access-token
identity-ua
docs
api-reference/endpoints
environments
folders
identities
organizations
secret-imports
service-tokens
workspaces
contributing/platform/backend
documentation/platform/identities
integrations/platforms
mint.jsonself-hosting
spec.yamlfrontend/src
components/signup
views
Settings
PersonalSettingsPage/APIKeySection
ProjectSettingsPage/components/WebhooksTab
admin/SignUpPage
12
.env.example
12
.env.example
@ -3,16 +3,18 @@
|
||||
# THIS IS A SAMPLE ENCRYPTION KEY AND SHOULD NEVER BE USED FOR PRODUCTION
|
||||
ENCRYPTION_KEY=6c1fe4e407b8911c104518103505b218
|
||||
|
||||
# Required
|
||||
DB_CONNECTION_URI=postgres://infisical:infisical@db:5432/infisical
|
||||
|
||||
# JWT
|
||||
# Required secrets to sign JWT tokens
|
||||
# THIS IS A SAMPLE AUTH_SECRET KEY AND SHOULD NEVER BE USED FOR PRODUCTION
|
||||
AUTH_SECRET=5lrMXKKWCVocS/uerPsl7V+TX/aaUaI7iDkgl3tSmLE=
|
||||
|
||||
# MongoDB
|
||||
# Backend will connect to the MongoDB instance at connection string MONGO_URL which can either be a ref
|
||||
# to the MongoDB container instance or Mongo Cloud
|
||||
# Required
|
||||
MONGO_URL=mongodb://root:example@mongo:27017/?authSource=admin
|
||||
# Postgres creds
|
||||
POSTGRES_PASSWORD=infisical
|
||||
POSTGRES_USER=infisical
|
||||
POSTGRES_DB=infisical
|
||||
|
||||
# Redis
|
||||
REDIS_URL=redis://redis:6379
|
||||
|
1
.env.migration.example
Normal file
1
.env.migration.example
Normal file
@ -0,0 +1 @@
|
||||
DB_CONNECTION_URI=
|
@ -14,36 +14,62 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Node 20
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "20"
|
||||
# uncomment this when testing locally using nektos/act
|
||||
# - uses: KengoTODA/actions-setup-docker-compose@v1
|
||||
# if: ${{ env.ACT }}
|
||||
# name: Install `docker-compose` for local simulations
|
||||
# - name: Setup Node 20
|
||||
# uses: actions/setup-node@v3
|
||||
# with:
|
||||
# version: "2.14.2"
|
||||
# node-version: "20"
|
||||
# uncomment this when testing locally using nektos/act
|
||||
- uses: KengoTODA/actions-setup-docker-compose@v1
|
||||
if: ${{ env.ACT }}
|
||||
name: Install `docker-compose` for local simulations
|
||||
with:
|
||||
version: "2.14.2"
|
||||
- name: 📦Build the latest image
|
||||
run: docker build --tag infisical-api .
|
||||
working-directory: backend
|
||||
- name: Start postgres and redis
|
||||
run: touch .env && docker-compose -f docker-compose.pg.yml up -d db redis
|
||||
run: touch .env && docker-compose -f docker-compose.dev.yml up -d db redis
|
||||
- name: Start the server
|
||||
run: docker run --name infisical-api -d -p 4000:4000 -e DB_CONNECTION_URI=$DB_CONNECTION_URI -e REDIS_URL=$REDIS_URL -e JWT_AUTH_SECRET=$JWT_AUTH_SECRET --entrypoint '/bin/sh' infisical-api -c "npm run migration:latest && ls && node dist/main.mjs"
|
||||
run: |
|
||||
echo "SECRET_SCANNING_GIT_APP_ID=793712" >> .env
|
||||
echo "SECRET_SCANNING_PRIVATE_KEY=some-random" >> .env
|
||||
echo "SECRET_SCANNING_WEBHOOK_SECRET=some-random" >> .env
|
||||
docker run --name infisical-api -d -p 4000:4000 -e DB_CONNECTION_URI=$DB_CONNECTION_URI -e REDIS_URL=$REDIS_URL -e JWT_AUTH_SECRET=$JWT_AUTH_SECRET --env-file .env --entrypoint '/bin/sh' infisical-api -c "npm run migration:latest && ls && node dist/main.mjs"
|
||||
env:
|
||||
REDIS_URL: redis://172.17.0.1:6379
|
||||
DB_CONNECTION_URI: postgres://infisical:infisical@172.17.0.1:5432/infisical?sslmode=disable
|
||||
JWT_AUTH_SECRET: something-random
|
||||
- name: Install openapi api diff
|
||||
run: npm install -g openapi-diff
|
||||
- name: Wait for containers to be stable
|
||||
run: timeout 60s sh -c 'until docker ps | grep infisical-api | grep -q healthy; do echo "Waiting for container to be healthy..."; sleep 2; done'
|
||||
- name: Get changes made in API
|
||||
id: openapi-diff
|
||||
run: openapi-diff https://app.infisical.com/api/docs/json http://localhost:4000/api/docs/json
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21.5'
|
||||
- name: Wait for container to be stable and check logs
|
||||
run: |
|
||||
SECONDS=0
|
||||
HEALTHY=0
|
||||
while [ $SECONDS -lt 60 ]; do
|
||||
if docker ps | grep infisical-api | grep -q healthy; then
|
||||
echo "Container is healthy."
|
||||
HEALTHY=1
|
||||
break
|
||||
fi
|
||||
echo "Waiting for container to be healthy... ($SECONDS seconds elapsed)"
|
||||
|
||||
docker logs infisical-api
|
||||
|
||||
sleep 2
|
||||
SECONDS=$((SECONDS+2))
|
||||
done
|
||||
|
||||
if [ $HEALTHY -ne 1 ]; then
|
||||
echo "Container did not become healthy in time"
|
||||
exit 1
|
||||
fi
|
||||
- name: Install openapi-diff
|
||||
run: go install github.com/tufin/oasdiff@latest
|
||||
- name: Running OpenAPI Spec diff action
|
||||
run: oasdiff breaking https://app.infisical.com/api/docs/json http://localhost:4000/api/docs/json --fail-on ERR
|
||||
- name: cleanup
|
||||
run: |
|
||||
docker-compose -f "docker-compose.pg.yml" down
|
||||
run: |
|
||||
docker-compose -f "docker-compose.dev.yml" down
|
||||
docker stop infisical-api
|
||||
docker remove infisical-api
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -6,7 +6,7 @@ node_modules
|
||||
.env.gamma
|
||||
.env.prod
|
||||
.env.infisical
|
||||
|
||||
.env.migration
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
|
10
Makefile
10
Makefile
@ -5,16 +5,10 @@ push:
|
||||
docker-compose -f docker-compose.yml push
|
||||
|
||||
up-dev:
|
||||
docker-compose -f docker-compose.dev.yml up --build
|
||||
|
||||
up-pg-dev:
|
||||
docker compose -f docker-compose.pg.yml up --build
|
||||
|
||||
i-dev:
|
||||
infisical run -- docker-compose -f docker-compose.dev.yml up --build
|
||||
docker compose -f docker-compose.dev.yml up --build
|
||||
|
||||
up-prod:
|
||||
docker-compose -f docker-compose.yml up --build
|
||||
docker-compose -f docker-compose.prod.yml up --build
|
||||
|
||||
down:
|
||||
docker-compose down
|
||||
|
@ -84,13 +84,13 @@ To set up and run Infisical locally, make sure you have Git and Docker installed
|
||||
Linux/macOS:
|
||||
|
||||
```console
|
||||
git clone https://github.com/Infisical/infisical && cd "$(basename $_ .git)" && cp .env.example .env && docker-compose -f docker-compose.yml up
|
||||
git clone https://github.com/Infisical/infisical && cd "$(basename $_ .git)" && cp .env.example .env && docker-compose -f docker-compose.prod.yml up
|
||||
```
|
||||
|
||||
Windows Command Prompt:
|
||||
|
||||
```console
|
||||
git clone https://github.com/Infisical/infisical && cd infisical && copy .env.example .env && docker-compose -f docker-compose.yml up
|
||||
git clone https://github.com/Infisical/infisical && cd infisical && copy .env.example .env && docker-compose -f docker-compose.prod.yml up
|
||||
```
|
||||
|
||||
Create an account at `http://localhost:80`
|
||||
|
3
backend/package-lock.json
generated
3
backend/package-lock.json
generated
@ -48,7 +48,8 @@
|
||||
"mysql2": "^3.6.5",
|
||||
"nanoid": "^5.0.4",
|
||||
"node-cache": "^5.1.2",
|
||||
"nodemailer": "^6.9.7",
|
||||
"nodemailer": "^6.9.9",
|
||||
"ora": "^7.0.1",
|
||||
"passport-github": "^1.1.0",
|
||||
"passport-gitlab2": "^5.0.0",
|
||||
"passport-google-oauth20": "^2.0.0",
|
||||
|
@ -109,7 +109,8 @@
|
||||
"mysql2": "^3.6.5",
|
||||
"nanoid": "^5.0.4",
|
||||
"node-cache": "^5.1.2",
|
||||
"nodemailer": "^6.9.7",
|
||||
"nodemailer": "^6.9.9",
|
||||
"ora": "^7.0.1",
|
||||
"passport-github": "^1.1.0",
|
||||
"passport-gitlab2": "^5.0.0",
|
||||
"passport-google-oauth20": "^2.0.0",
|
||||
|
@ -3,13 +3,9 @@ import dotenv from "dotenv";
|
||||
import path from "path";
|
||||
import knex from "knex";
|
||||
import { writeFileSync } from "fs";
|
||||
import promptSync from "prompt-sync";
|
||||
|
||||
const prompt = promptSync({ sigint: true });
|
||||
|
||||
dotenv.config({
|
||||
path: path.join(__dirname, "../.env"),
|
||||
debug: true
|
||||
path: path.join(__dirname, "../../.env.migration")
|
||||
});
|
||||
|
||||
const db = knex({
|
||||
@ -94,17 +90,7 @@ const main = async () => {
|
||||
.orderBy("table_name")
|
||||
).filter((el) => !el.tableName.includes("_migrations"));
|
||||
|
||||
console.log("Select a table to generate schema");
|
||||
console.table(tables);
|
||||
console.log("all: all tables");
|
||||
const selectedTables = prompt("Type table numbers comma seperated: ");
|
||||
const tableNumbers =
|
||||
selectedTables !== "all" ? selectedTables.split(",").map((el) => Number(el)) : [];
|
||||
|
||||
for (let i = 0; i < tables.length; i += 1) {
|
||||
// skip if not desired table
|
||||
if (selectedTables !== "all" && !tableNumbers.includes(i)) continue;
|
||||
|
||||
const { tableName } = tables[i];
|
||||
const columns = await db(tableName).columnInfo();
|
||||
const columnNames = Object.keys(columns);
|
||||
@ -124,16 +110,16 @@ const main = async () => {
|
||||
if (colInfo.nullable) {
|
||||
ztype = ztype.concat(".nullable().optional()");
|
||||
}
|
||||
schema = schema.concat(`${!schema ? "\n" : ""} ${columnName}: ${ztype},\n`);
|
||||
schema = schema.concat(
|
||||
`${!schema ? "\n" : ""} ${columnName}: ${ztype}${colNum === columnNames.length - 1 ? "" : ","}\n`
|
||||
);
|
||||
}
|
||||
|
||||
const dashcase = tableName.split("_").join("-");
|
||||
const pascalCase = tableName
|
||||
.split("_")
|
||||
.reduce(
|
||||
(prev, curr) => prev + `${curr.at(0)?.toUpperCase()}${curr.slice(1).toLowerCase()}`,
|
||||
""
|
||||
);
|
||||
.reduce((prev, curr) => prev + `${curr.at(0)?.toUpperCase()}${curr.slice(1).toLowerCase()}`, "");
|
||||
|
||||
writeFileSync(
|
||||
path.join(__dirname, "../src/db/schemas", `${dashcase}.ts`),
|
||||
`// Code generated by automation script, DO NOT EDIT.
|
||||
@ -152,15 +138,6 @@ export type T${pascalCase}Insert = Omit<T${pascalCase}, TImmutableDBKeys>;
|
||||
export type T${pascalCase}Update = Partial<Omit<T${pascalCase}, TImmutableDBKeys>>;
|
||||
`
|
||||
);
|
||||
|
||||
// const file = readFileSync(path.join(__dirname, "../src/db/schemas/index.ts"), "utf8");
|
||||
// if (!file.includes(`export * from "./${dashcase};"`)) {
|
||||
// appendFileSync(
|
||||
// path.join(__dirname, "../src/db/schemas/index.ts"),
|
||||
// `\nexport * from "./${dashcase}";`,
|
||||
// "utf8"
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
|
@ -5,9 +5,9 @@ import dotenv from "dotenv";
|
||||
import type { Knex } from "knex";
|
||||
import path from "path";
|
||||
|
||||
// Update with your config settings.
|
||||
// Update with your config settings. .
|
||||
dotenv.config({
|
||||
path: path.join(__dirname, "../../.env"),
|
||||
path: path.join(__dirname, "../../../.env.migration"),
|
||||
debug: true
|
||||
});
|
||||
export default {
|
||||
|
@ -11,6 +11,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
method: "GET",
|
||||
url: "/:workspaceId/secret-snapshots",
|
||||
schema: {
|
||||
description: "Return project secret snapshots ids",
|
||||
security: [
|
||||
{
|
||||
apiKeyAuth: [],
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
workspaceId: z.string().trim()
|
||||
}),
|
||||
@ -74,6 +81,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
method: "GET",
|
||||
url: "/:workspaceId/audit-logs",
|
||||
schema: {
|
||||
description: "Return audit logs",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
workspaceId: z.string().trim()
|
||||
}),
|
||||
|
@ -19,7 +19,6 @@ import { BadRequestError } from "@app/lib/errors";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||
import { AuthMode } from "@app/services/auth/auth-type";
|
||||
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
|
||||
|
||||
type TSAMLConfig = {
|
||||
callbackUrl: string;
|
||||
@ -28,6 +27,7 @@ type TSAMLConfig = {
|
||||
cert: string;
|
||||
audience: string;
|
||||
wantAuthnResponseSigned?: boolean;
|
||||
disableRequestedAuthnContext?: boolean;
|
||||
};
|
||||
|
||||
export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
||||
@ -77,6 +77,7 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
||||
samlConfig.wantAuthnResponseSigned = false;
|
||||
}
|
||||
if (ssoConfig.authProvider === SamlProviders.AZURE_SAML) {
|
||||
samlConfig.disableRequestedAuthnContext = true;
|
||||
if (req.body?.RelayState && JSON.parse(req.body.RelayState).spInitiated) {
|
||||
samlConfig.audience = `spn:${ssoConfig.issuer}`;
|
||||
}
|
||||
@ -92,7 +93,6 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
||||
// eslint-disable-next-line
|
||||
async (req, profile, cb) => {
|
||||
try {
|
||||
const serverCfg = await getServerCfg();
|
||||
if (!profile) throw new BadRequestError({ message: "Missing profile" });
|
||||
const { firstName } = profile;
|
||||
const email = profile?.email ?? (profile?.emailAddress as string); // emailRippling is added because in Rippling the field `email` reserved
|
||||
@ -105,7 +105,6 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
||||
email,
|
||||
firstName: profile.firstName as string,
|
||||
lastName: profile.lastName as string,
|
||||
isSignupAllowed: Boolean(serverCfg.allowSignUp),
|
||||
relayState: (req.body as { RelayState?: string }).RelayState,
|
||||
authProvider: (req as unknown as FastifyRequest).ssoConfig?.authProvider as string,
|
||||
orgId: (req as unknown as FastifyRequest).ssoConfig?.orgId as string
|
||||
|
@ -57,6 +57,13 @@ export const registerSnapshotRouter = async (server: FastifyZodProvider) => {
|
||||
method: "POST",
|
||||
url: "/:secretSnapshotId/rollback",
|
||||
schema: {
|
||||
description: "Roll back project secrets to those captured in a secret snapshot version.",
|
||||
security: [
|
||||
{
|
||||
apiKeyAuth: [],
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
secretSnapshotId: z.string().trim()
|
||||
}),
|
||||
|
@ -300,19 +300,9 @@ export const samlConfigServiceFactory = ({
|
||||
};
|
||||
};
|
||||
|
||||
const samlLogin = async ({
|
||||
firstName,
|
||||
email,
|
||||
lastName,
|
||||
authProvider,
|
||||
orgId,
|
||||
relayState,
|
||||
isSignupAllowed
|
||||
}: TSamlLoginDTO) => {
|
||||
const samlLogin = async ({ firstName, email, lastName, authProvider, orgId, relayState }: TSamlLoginDTO) => {
|
||||
const appCfg = getConfig();
|
||||
let user = await userDAL.findUserByEmail(email);
|
||||
const isSamlSignUpDisabled = !isSignupAllowed && !user;
|
||||
if (isSamlSignUpDisabled) throw new BadRequestError({ message: "User signup disabled", name: "Saml SSO login" });
|
||||
|
||||
const organization = await orgDAL.findOrgById(orgId);
|
||||
if (!organization) throw new BadRequestError({ message: "Org not found" });
|
||||
|
@ -41,7 +41,6 @@ export type TSamlLoginDTO = {
|
||||
lastName?: string;
|
||||
authProvider: string;
|
||||
orgId: string;
|
||||
isSignupAllowed: boolean;
|
||||
// saml thingy
|
||||
relayState?: string;
|
||||
};
|
||||
|
@ -25,13 +25,13 @@ export const fastifySwagger = fp(async (fastify) => {
|
||||
],
|
||||
components: {
|
||||
securitySchemes: {
|
||||
bearer: {
|
||||
bearerAuth: {
|
||||
type: "http",
|
||||
scheme: "bearer",
|
||||
bearerFormat: "JWT",
|
||||
description: "A service token in Infisical"
|
||||
description: "An access token in Infisical"
|
||||
},
|
||||
apiKey: {
|
||||
apiKeyAuth: {
|
||||
type: "apiKey",
|
||||
in: "header",
|
||||
name: "X-API-Key",
|
||||
|
@ -72,7 +72,8 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
||||
200: z.object({
|
||||
message: z.string(),
|
||||
user: UsersSchema,
|
||||
token: z.string()
|
||||
token: z.string(),
|
||||
new: z.string()
|
||||
})
|
||||
}
|
||||
},
|
||||
@ -107,7 +108,8 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
||||
return {
|
||||
message: "Successfully set up admin account",
|
||||
user: user.user,
|
||||
token: token.access
|
||||
token: token.access,
|
||||
new: "123"
|
||||
};
|
||||
}
|
||||
});
|
||||
|
@ -5,6 +5,7 @@ export const registerIdentityAccessTokenRouter = async (server: FastifyZodProvid
|
||||
url: "/token/renew",
|
||||
method: "POST",
|
||||
schema: {
|
||||
description: "Renew access token",
|
||||
body: z.object({
|
||||
accessToken: z.string().trim()
|
||||
}),
|
||||
|
@ -11,6 +11,12 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
||||
url: "/",
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
schema: {
|
||||
description: "Create identity",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
body: z.object({
|
||||
name: z.string().trim(),
|
||||
organizationId: z.string().trim(),
|
||||
@ -52,6 +58,12 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
||||
url: "/:identityId",
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
schema: {
|
||||
description: "Update identity",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
identityId: z.string()
|
||||
}),
|
||||
@ -95,6 +107,12 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
||||
url: "/:identityId",
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
schema: {
|
||||
description: "Delete identity",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
identityId: z.string()
|
||||
}),
|
||||
|
@ -24,6 +24,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
||||
url: "/universal-auth/login",
|
||||
method: "POST",
|
||||
schema: {
|
||||
description: "Login with Universal Auth",
|
||||
body: z.object({
|
||||
clientId: z.string().trim(),
|
||||
clientSecret: z.string().trim()
|
||||
@ -67,6 +68,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
||||
method: "POST",
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Attach Universal Auth configuration onto identity",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
identityId: z.string().trim()
|
||||
}),
|
||||
@ -141,6 +148,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
||||
method: "PATCH",
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Update Universal Auth configuration on identity",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
identityId: z.string()
|
||||
}),
|
||||
@ -209,6 +222,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
||||
method: "GET",
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Retrieve Universal Auth configuration on identity",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
identityId: z.string()
|
||||
}),
|
||||
@ -246,6 +265,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
||||
method: "POST",
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Create Universal Auth Client Secret for identity",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
identityId: z.string()
|
||||
}),
|
||||
@ -291,6 +316,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
||||
method: "GET",
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "List Universal Auth Client Secrets for identity",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
identityId: z.string()
|
||||
}),
|
||||
@ -327,6 +358,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
||||
method: "POST",
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Revoke Universal Auth Client Secrets for identity",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
identityId: z.string(),
|
||||
clientSecretId: z.string()
|
||||
|
@ -10,6 +10,13 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
|
||||
url: "/:workspaceId/environments",
|
||||
method: "POST",
|
||||
schema: {
|
||||
description: "Create environment",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
workspaceId: z.string().trim()
|
||||
}),
|
||||
@ -58,6 +65,13 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
|
||||
url: "/:workspaceId/environments/:id",
|
||||
method: "PATCH",
|
||||
schema: {
|
||||
description: "Update environment",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
workspaceId: z.string().trim(),
|
||||
id: z.string().trim()
|
||||
@ -114,6 +128,13 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
|
||||
url: "/:workspaceId/environments/:id",
|
||||
method: "DELETE",
|
||||
schema: {
|
||||
description: "Delete environment",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
workspaceId: z.string().trim(),
|
||||
id: z.string().trim()
|
||||
|
@ -10,6 +10,13 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
||||
url: "/:workspaceId/memberships",
|
||||
method: "GET",
|
||||
schema: {
|
||||
description: "Return project user memberships",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
workspaceId: z.string().trim()
|
||||
}),
|
||||
@ -96,6 +103,13 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
||||
url: "/:workspaceId/memberships/:membershipId",
|
||||
method: "PATCH",
|
||||
schema: {
|
||||
description: "Update project user membership",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
workspaceId: z.string().trim(),
|
||||
membershipId: z.string().trim()
|
||||
@ -141,6 +155,13 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
||||
url: "/:workspaceId/memberships/:membershipId",
|
||||
method: "DELETE",
|
||||
schema: {
|
||||
description: "Delete project user membership",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
workspaceId: z.string().trim(),
|
||||
membershipId: z.string().trim()
|
||||
|
@ -11,6 +11,13 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
||||
url: "/",
|
||||
method: "POST",
|
||||
schema: {
|
||||
description: "Create folders",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
body: z.object({
|
||||
workspaceId: z.string().trim(),
|
||||
environment: z.string().trim(),
|
||||
@ -57,6 +64,13 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
||||
url: "/:folderId",
|
||||
method: "PATCH",
|
||||
schema: {
|
||||
description: "Update folder",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
// old way this was name
|
||||
folderId: z.string()
|
||||
@ -109,6 +123,13 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
||||
url: "/:folderId",
|
||||
method: "DELETE",
|
||||
schema: {
|
||||
description: "Delete a folder",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
folderId: z.string()
|
||||
}),
|
||||
@ -158,6 +179,13 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
||||
url: "/",
|
||||
method: "GET",
|
||||
schema: {
|
||||
description: "Get folders",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
querystring: z.object({
|
||||
workspaceId: z.string().trim(),
|
||||
environment: z.string().trim(),
|
||||
|
@ -11,6 +11,13 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
||||
url: "/",
|
||||
method: "POST",
|
||||
schema: {
|
||||
description: "Create secret imports",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
body: z.object({
|
||||
workspaceId: z.string().trim(),
|
||||
environment: z.string().trim(),
|
||||
@ -65,6 +72,13 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
||||
url: "/:secretImportId",
|
||||
method: "PATCH",
|
||||
schema: {
|
||||
description: "Update secret imports",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
secretImportId: z.string().trim()
|
||||
}),
|
||||
@ -128,6 +142,13 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
||||
url: "/:secretImportId",
|
||||
method: "DELETE",
|
||||
schema: {
|
||||
description: "Delete secret imports",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
secretImportId: z.string().trim()
|
||||
}),
|
||||
@ -181,6 +202,13 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
||||
url: "/",
|
||||
method: "GET",
|
||||
schema: {
|
||||
description: "Get secret imports",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
querystring: z.object({
|
||||
workspaceId: z.string().trim(),
|
||||
environment: z.string().trim(),
|
||||
|
@ -10,6 +10,13 @@ export const registerIdentityOrgRouter = async (server: FastifyZodProvider) => {
|
||||
url: "/:orgId/identity-memberships",
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Return organization identity memberships",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
orgId: z.string().trim()
|
||||
}),
|
||||
|
@ -46,6 +46,12 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
|
||||
url: "/:projectId/identity-memberships/:identityId",
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Update project identity memberships",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
projectId: z.string().trim(),
|
||||
identityId: z.string().trim()
|
||||
@ -77,6 +83,12 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
|
||||
url: "/:projectId/identity-memberships/:identityId",
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Delete project identity memberships",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
projectId: z.string().trim(),
|
||||
identityId: z.string().trim()
|
||||
@ -104,6 +116,12 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
|
||||
url: "/:projectId/identity-memberships",
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Return project identity memberships",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
projectId: z.string().trim()
|
||||
}),
|
||||
|
@ -9,6 +9,13 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
||||
method: "GET",
|
||||
url: "/:organizationId/memberships",
|
||||
schema: {
|
||||
description: "Return organization user memberships",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
organizationId: z.string().trim()
|
||||
}),
|
||||
@ -46,6 +53,13 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
||||
method: "GET",
|
||||
url: "/:organizationId/workspaces",
|
||||
schema: {
|
||||
description: "Return projects in organization that user is part of",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
organizationId: z.string().trim()
|
||||
}),
|
||||
@ -84,6 +98,13 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
||||
method: "PATCH",
|
||||
url: "/:organizationId/memberships/:membershipId",
|
||||
schema: {
|
||||
description: "Update organization user memberships",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({ organizationId: z.string().trim(), membershipId: z.string().trim() }),
|
||||
body: z.object({
|
||||
role: z.string().trim()
|
||||
@ -113,6 +134,13 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
||||
method: "DELETE",
|
||||
url: "/:organizationId/memberships/:membershipId",
|
||||
schema: {
|
||||
description: "Delete organization user memberships",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({ organizationId: z.string().trim(), membershipId: z.string().trim() }),
|
||||
response: {
|
||||
200: z.object({
|
||||
|
@ -10,6 +10,12 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
url: "/:workspaceId/encrypted-key",
|
||||
method: "GET",
|
||||
schema: {
|
||||
description: "Return encrypted project key",
|
||||
security: [
|
||||
{
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
workspaceId: z.string().trim()
|
||||
}),
|
||||
|
@ -21,6 +21,12 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
|
||||
method: "GET",
|
||||
onRequest: verifyAuth([AuthMode.SERVICE_TOKEN]),
|
||||
schema: {
|
||||
description: "Return Infisical Token data",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
response: {
|
||||
200: ServiceTokensSchema.merge(
|
||||
z.object({
|
||||
|
@ -71,6 +71,12 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
|
||||
method: "GET",
|
||||
url: "/me/organizations",
|
||||
schema: {
|
||||
description: "Return organizations that current user is part of",
|
||||
security: [
|
||||
{
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
response: {
|
||||
200: z.object({
|
||||
organizations: OrganizationsSchema.array()
|
||||
@ -179,6 +185,12 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
|
||||
method: "GET",
|
||||
url: "/me",
|
||||
schema: {
|
||||
description: "Retrieve the current user on the request",
|
||||
security: [
|
||||
{
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
response: {
|
||||
200: z.object({
|
||||
user: UsersSchema.merge(UserEncryptionKeysSchema.omit({ verifier: true }))
|
||||
|
@ -38,6 +38,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
url: "/raw",
|
||||
method: "GET",
|
||||
schema: {
|
||||
description: "List secrets",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
querystring: z.object({
|
||||
workspaceId: z.string().trim().optional(),
|
||||
environment: z.string().trim().optional(),
|
||||
@ -121,6 +128,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
url: "/raw/:secretName",
|
||||
method: "GET",
|
||||
schema: {
|
||||
description: "Get a secret by name",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
secretName: z.string().trim()
|
||||
}),
|
||||
@ -204,6 +218,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
url: "/raw/:secretName",
|
||||
method: "POST",
|
||||
schema: {
|
||||
description: "Create secret",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
secretName: z.string().trim()
|
||||
}),
|
||||
@ -274,6 +295,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
url: "/raw/:secretName",
|
||||
method: "PATCH",
|
||||
schema: {
|
||||
description: "Update secret",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
secretName: z.string().trim()
|
||||
}),
|
||||
@ -341,6 +369,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
url: "/raw/:secretName",
|
||||
method: "DELETE",
|
||||
schema: {
|
||||
description: "Delete secret",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
apiKeyAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
secretName: z.string().trim()
|
||||
}),
|
||||
|
@ -156,7 +156,19 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
|
||||
const { user, accessToken, refreshToken } = await server.services.signup.completeAccountInvite({
|
||||
...req.body,
|
||||
ip: req.realIp,
|
||||
userAgent
|
||||
userAgent,
|
||||
authorization: req.headers.authorization as string
|
||||
});
|
||||
|
||||
void server.services.telemetry.sendLoopsEvent(user.email, user.firstName || "", user.lastName || "");
|
||||
|
||||
void server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.UserSignedUp,
|
||||
distinctId: user.email,
|
||||
properties: {
|
||||
email: user.email,
|
||||
attributionSource: "Team Invite"
|
||||
}
|
||||
});
|
||||
|
||||
void res.setCookie("jid", refreshToken, {
|
||||
|
@ -212,13 +212,16 @@ export const authSignupServiceFactory = ({
|
||||
protectedKeyTag,
|
||||
encryptedPrivateKey,
|
||||
encryptedPrivateKeyIV,
|
||||
encryptedPrivateKeyTag
|
||||
encryptedPrivateKeyTag,
|
||||
authorization
|
||||
}: TCompleteAccountInviteDTO) => {
|
||||
const user = await userDAL.findUserByEmail(email);
|
||||
if (!user || (user && user.isAccepted)) {
|
||||
throw new Error("Failed to complete account for complete user");
|
||||
}
|
||||
|
||||
validateSignUpAuthorization(authorization, user.id);
|
||||
|
||||
const [orgMembership] = await orgDAL.findMembership({
|
||||
inviteEmail: email,
|
||||
status: OrgMembershipStatus.Invited
|
||||
|
@ -34,4 +34,5 @@ export type TCompleteAccountInviteDTO = {
|
||||
verifier: string;
|
||||
ip: string;
|
||||
userAgent: string;
|
||||
authorization: string;
|
||||
};
|
||||
|
@ -35,12 +35,12 @@ export const identityAccessTokenServiceFactory = ({
|
||||
}
|
||||
|
||||
// ttl check
|
||||
if (accessTokenTTL > 0) {
|
||||
if (Number(accessTokenTTL) > 0) {
|
||||
const currentDate = new Date();
|
||||
if (accessTokenLastRenewedAt) {
|
||||
// access token has been renewed
|
||||
const accessTokenRenewed = new Date(accessTokenLastRenewedAt);
|
||||
const ttlInMilliseconds = accessTokenTTL * 1000;
|
||||
const ttlInMilliseconds = Number(accessTokenTTL) * 1000;
|
||||
const expirationDate = new Date(accessTokenRenewed.getTime() + ttlInMilliseconds);
|
||||
|
||||
if (currentDate > expirationDate)
|
||||
@ -50,7 +50,7 @@ export const identityAccessTokenServiceFactory = ({
|
||||
} else {
|
||||
// access token has never been renewed
|
||||
const accessTokenCreated = new Date(accessTokenCreatedAt);
|
||||
const ttlInMilliseconds = accessTokenTTL * 1000;
|
||||
const ttlInMilliseconds = Number(accessTokenTTL) * 1000;
|
||||
const expirationDate = new Date(accessTokenCreated.getTime() + ttlInMilliseconds);
|
||||
|
||||
if (currentDate > expirationDate)
|
||||
@ -61,9 +61,9 @@ export const identityAccessTokenServiceFactory = ({
|
||||
}
|
||||
|
||||
// max ttl checks
|
||||
if (accessTokenMaxTTL > 0) {
|
||||
if (Number(accessTokenMaxTTL) > 0) {
|
||||
const accessTokenCreated = new Date(accessTokenCreatedAt);
|
||||
const ttlInMilliseconds = accessTokenMaxTTL * 1000;
|
||||
const ttlInMilliseconds = Number(accessTokenMaxTTL) * 1000;
|
||||
const currentDate = new Date();
|
||||
const expirationDate = new Date(accessTokenCreated.getTime() + ttlInMilliseconds);
|
||||
|
||||
@ -72,7 +72,7 @@ export const identityAccessTokenServiceFactory = ({
|
||||
message: "Failed to renew MI access token due to Max TTL expiration"
|
||||
});
|
||||
|
||||
const extendToDate = new Date(currentDate.getTime() + accessTokenTTL);
|
||||
const extendToDate = new Date(currentDate.getTime() + Number(accessTokenTTL));
|
||||
if (extendToDate > expirationDate)
|
||||
throw new UnauthorizedError({
|
||||
message: "Failed to renew MI access token past its Max TTL expiration"
|
||||
|
@ -69,9 +69,9 @@ export const identityUaServiceFactory = ({
|
||||
if (!validClientSecretInfo) throw new UnauthorizedError();
|
||||
|
||||
const { clientSecretTTL, clientSecretNumUses, clientSecretNumUsesLimit } = validClientSecretInfo;
|
||||
if (clientSecretTTL > 0) {
|
||||
if (Number(clientSecretTTL) > 0) {
|
||||
const clientSecretCreated = new Date(validClientSecretInfo.createdAt);
|
||||
const ttlInMilliseconds = clientSecretTTL * 1000;
|
||||
const ttlInMilliseconds = Number(clientSecretTTL) * 1000;
|
||||
const currentDate = new Date();
|
||||
const expirationTime = new Date(clientSecretCreated.getTime() + ttlInMilliseconds);
|
||||
|
||||
@ -124,7 +124,10 @@ export const identityUaServiceFactory = ({
|
||||
} as TIdentityAccessTokenJwtPayload,
|
||||
appCfg.AUTH_SECRET,
|
||||
{
|
||||
expiresIn: identityAccessToken.accessTokenMaxTTL === 0 ? undefined : identityAccessToken.accessTokenMaxTTL
|
||||
expiresIn:
|
||||
Number(identityAccessToken.accessTokenMaxTTL) === 0
|
||||
? undefined
|
||||
: Number(identityAccessToken.accessTokenMaxTTL)
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: '3'
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
nginx:
|
||||
@ -10,36 +10,84 @@ services:
|
||||
volumes:
|
||||
- ./nginx/default.dev.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
depends_on:
|
||||
- frontend
|
||||
- backend
|
||||
networks:
|
||||
- infisical-dev
|
||||
- frontend
|
||||
|
||||
backend:
|
||||
container_name: infisical-dev-backend
|
||||
restart: unless-stopped
|
||||
db:
|
||||
image: postgres:14-alpine
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_PASSWORD: infisical
|
||||
POSTGRES_USER: infisical
|
||||
POSTGRES_DB: infisical
|
||||
|
||||
redis:
|
||||
image: redis
|
||||
container_name: infisical-dev-redis
|
||||
environment:
|
||||
- ALLOW_EMPTY_PASSWORD=yes
|
||||
ports:
|
||||
- 6379:6379
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
|
||||
redis-commander:
|
||||
container_name: infisical-dev-redis-commander
|
||||
image: rediscommander/redis-commander
|
||||
restart: always
|
||||
depends_on:
|
||||
- mongo
|
||||
- smtp-server
|
||||
- redis
|
||||
environment:
|
||||
- REDIS_HOSTS=local:redis:6379
|
||||
ports:
|
||||
- "8085:8081"
|
||||
|
||||
db-test:
|
||||
profiles: ["test"]
|
||||
image: postgres:14-alpine
|
||||
ports:
|
||||
- "5430:5432"
|
||||
environment:
|
||||
POSTGRES_PASSWORD: infisical
|
||||
POSTGRES_USER: infisical
|
||||
POSTGRES_DB: infisical-test
|
||||
|
||||
db-migration:
|
||||
container_name: infisical-db-migration
|
||||
depends_on:
|
||||
- db
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
volumes:
|
||||
- ./backend/src:/app/src
|
||||
- ./backend/nodemon.json:/app/nodemon.json
|
||||
- /app/node_modules
|
||||
- ./backend/api-documentation.json:/app/api-documentation.json
|
||||
- ./backend/swagger.ts:/app/swagger.ts
|
||||
command: npm run dev
|
||||
dockerfile: Dockerfile.dev
|
||||
env_file: .env
|
||||
environment:
|
||||
- DB_CONNECTION_URI=postgres://infisical:infisical@db/infisical?sslmode=disable
|
||||
command: npm run migration:latest
|
||||
|
||||
backend:
|
||||
container_name: infisical-dev-api
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile.dev
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_started
|
||||
redis:
|
||||
condition: service_started
|
||||
db-migration:
|
||||
condition: service_completed_successfully
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- 4000:4000
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- MONGO_URL=mongodb://root:example@mongo:27017/?authSource=admin
|
||||
networks:
|
||||
- infisical-dev
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
- DB_CONNECTION_URI=postgres://infisical:infisical@db/infisical?sslmode=disable
|
||||
volumes:
|
||||
- ./backend/src:/app/src
|
||||
|
||||
frontend:
|
||||
container_name: infisical-dev-frontend
|
||||
@ -55,81 +103,31 @@ services:
|
||||
env_file: .env
|
||||
environment:
|
||||
- NEXT_PUBLIC_ENV=development
|
||||
- INFISICAL_TELEMETRY_ENABLED=${TELEMETRY_ENABLED}
|
||||
networks:
|
||||
- infisical-dev
|
||||
- INFISICAL_TELEMETRY_ENABLED=false
|
||||
|
||||
mongo:
|
||||
image: mongo
|
||||
container_name: infisical-dev-mongo
|
||||
pgadmin:
|
||||
image: dpage/pgadmin4
|
||||
restart: always
|
||||
env_file: .env
|
||||
environment:
|
||||
- MONGO_INITDB_ROOT_USERNAME=root
|
||||
- MONGO_INITDB_ROOT_PASSWORD=example
|
||||
volumes:
|
||||
- mongo-data:/data/db
|
||||
networks:
|
||||
- infisical-dev
|
||||
|
||||
mongo-express:
|
||||
container_name: infisical-dev-mongo-express
|
||||
image: mongo-express
|
||||
restart: always
|
||||
depends_on:
|
||||
- mongo
|
||||
env_file: .env
|
||||
environment:
|
||||
- ME_CONFIG_MONGODB_ADMINUSERNAME=root
|
||||
- ME_CONFIG_MONGODB_ADMINPASSWORD=example
|
||||
- ME_CONFIG_MONGODB_URL=mongodb://root:example@mongo:27017/
|
||||
PGADMIN_DEFAULT_EMAIL: admin@example.com
|
||||
PGADMIN_DEFAULT_PASSWORD: pass
|
||||
ports:
|
||||
- 8081:8081
|
||||
networks:
|
||||
- infisical-dev
|
||||
- 5050:80
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
smtp-server:
|
||||
container_name: infisical-dev-smtp-server
|
||||
image: lytrax/mailhog:latest # https://github.com/mailhog/MailHog/issues/353#issuecomment-821137362
|
||||
restart: always
|
||||
logging:
|
||||
driver: 'none' # disable saving logs
|
||||
driver: "none" # disable saving logs
|
||||
ports:
|
||||
- 1025:1025 # SMTP server
|
||||
- 8025:8025 # Web UI
|
||||
networks:
|
||||
- infisical-dev
|
||||
|
||||
redis:
|
||||
image: redis
|
||||
container_name: infisical-dev-redis
|
||||
environment:
|
||||
- ALLOW_EMPTY_PASSWORD=yes
|
||||
ports:
|
||||
- 6379:6379
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- infisical-dev
|
||||
|
||||
redis-commander:
|
||||
container_name: infisical-dev-redis-commander
|
||||
image: rediscommander/redis-commander
|
||||
restart: always
|
||||
depends_on:
|
||||
- redis
|
||||
environment:
|
||||
- REDIS_HOSTS=local:redis:6379
|
||||
ports:
|
||||
- "8085:8081"
|
||||
networks:
|
||||
- infisical-dev
|
||||
|
||||
volumes:
|
||||
mongo-data:
|
||||
postgres-data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
infisical-dev:
|
||||
|
@ -1,146 +0,0 @@
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
nginx:
|
||||
container_name: infisical-dev-nginx
|
||||
image: nginx
|
||||
restart: always
|
||||
ports:
|
||||
- 8080:80
|
||||
volumes:
|
||||
- ./nginx/default.dev.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
depends_on:
|
||||
- backend
|
||||
- frontend
|
||||
|
||||
db:
|
||||
image: postgres:14-alpine
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_PASSWORD: infisical
|
||||
POSTGRES_USER: infisical
|
||||
POSTGRES_DB: infisical
|
||||
|
||||
redis:
|
||||
image: redis
|
||||
container_name: infisical-dev-redis
|
||||
environment:
|
||||
- ALLOW_EMPTY_PASSWORD=yes
|
||||
ports:
|
||||
- 6379:6379
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
|
||||
redis-commander:
|
||||
container_name: infisical-dev-redis-commander
|
||||
image: rediscommander/redis-commander
|
||||
restart: always
|
||||
depends_on:
|
||||
- redis
|
||||
environment:
|
||||
- REDIS_HOSTS=local:redis:6379
|
||||
ports:
|
||||
- "8085:8081"
|
||||
|
||||
db-test:
|
||||
profiles: ["test"]
|
||||
image: postgres:14-alpine
|
||||
ports:
|
||||
- "5430:5432"
|
||||
environment:
|
||||
POSTGRES_PASSWORD: infisical
|
||||
POSTGRES_USER: infisical
|
||||
POSTGRES_DB: infisical-test
|
||||
|
||||
backend:
|
||||
container_name: infisical-dev-api
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile.dev
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- 4000:4000
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- DB_CONNECTION_URI=postgres://infisical:infisical@db/infisical?sslmode=disable
|
||||
volumes:
|
||||
- ./backend/src:/app/src
|
||||
|
||||
frontend:
|
||||
container_name: infisical-dev-frontend
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- backend
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile.dev
|
||||
volumes:
|
||||
- ./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
|
||||
restart: always
|
||||
environment:
|
||||
PGADMIN_DEFAULT_EMAIL: admin@example.com
|
||||
PGADMIN_DEFAULT_PASSWORD: pass
|
||||
ports:
|
||||
- 5050:80
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
smtp-server:
|
||||
container_name: infisical-dev-smtp-server
|
||||
image: lytrax/mailhog:latest # https://github.com/mailhog/MailHog/issues/353#issuecomment-821137362
|
||||
restart: always
|
||||
logging:
|
||||
driver: "none" # disable saving logs
|
||||
ports:
|
||||
- 1025:1025 # SMTP server
|
||||
- 8025:8025 # Web UI
|
||||
|
||||
# mongo:
|
||||
# image: mongo
|
||||
# container_name: infisical-dev-mongo
|
||||
# restart: always
|
||||
# env_file: .env
|
||||
# environment:
|
||||
# - MONGO_INITDB_ROOT_USERNAME=root
|
||||
# - MONGO_INITDB_ROOT_PASSWORD=example
|
||||
# volumes:
|
||||
# - mongo-data:/data/db
|
||||
# ports:
|
||||
# - 27017:27017
|
||||
#
|
||||
# mongo-express:
|
||||
# container_name: infisical-dev-mongo-express
|
||||
# image: mongo-express
|
||||
# restart: always
|
||||
# depends_on:
|
||||
# - mongo
|
||||
# env_file: .env
|
||||
# environment:
|
||||
# - ME_CONFIG_MONGODB_ADMINUSERNAME=root
|
||||
# - ME_CONFIG_MONGODB_ADMINPASSWORD=example
|
||||
# - ME_CONFIG_MONGODB_URL=mongodb://root:example@mongo:27017/
|
||||
# ports:
|
||||
# - 8081:8081
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
mongo-data:
|
||||
driver: local
|
@ -1,12 +1,27 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
db-migration:
|
||||
container_name: infisical-db-migration
|
||||
depends_on:
|
||||
- db
|
||||
image: infisical/infisical:latest-postgres
|
||||
env_file: .env
|
||||
command: npm run migration:latest
|
||||
networks:
|
||||
- infisical
|
||||
|
||||
backend:
|
||||
container_name: infisical-backend
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- mongo
|
||||
image: infisical/infisical:latest
|
||||
db:
|
||||
condition: service_started
|
||||
redis:
|
||||
condition: service_started
|
||||
db-migration:
|
||||
condition: service_completed_successfully
|
||||
image: infisical/infisical:latest-postgres
|
||||
env_file: .env
|
||||
ports:
|
||||
- 80:8080
|
||||
@ -28,21 +43,18 @@ services:
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
|
||||
mongo:
|
||||
container_name: infisical-mongo
|
||||
image: mongo
|
||||
db:
|
||||
container_name: infisical-db
|
||||
image: postgres:14-alpine
|
||||
restart: always
|
||||
env_file: .env
|
||||
environment:
|
||||
- MONGO_INITDB_ROOT_USERNAME=${MONGO_USERNAME}
|
||||
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD}
|
||||
volumes:
|
||||
- mongo-data:/data/db
|
||||
- pg_data:/data/db
|
||||
networks:
|
||||
- infisical
|
||||
|
||||
volumes:
|
||||
mongo-data:
|
||||
pg_data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Create"
|
||||
openapi: "POST /api/v2/workspace/{workspaceId}/environments"
|
||||
openapi: "POST /api/v1/workspace/{workspaceId}/environments"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Delete"
|
||||
openapi: "DELETE /api/v2/workspace/{workspaceId}/environments"
|
||||
---
|
||||
openapi: "DELETE /api/v1/workspace/{workspaceId}/environments/{id}"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Update"
|
||||
openapi: "PUT /api/v2/workspace/{workspaceId}/environments"
|
||||
---
|
||||
openapi: "PATCH /api/v1/workspace/{workspaceId}/environments/{id}"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Create"
|
||||
openapi: "POST /api/v1/folders/"
|
||||
---
|
||||
openapi: "POST /api/v1/folders"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Delete"
|
||||
openapi: "DELETE /api/v1/folders/{folderName}"
|
||||
---
|
||||
openapi: "DELETE /api/v1/folders/{folderId}"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "List"
|
||||
openapi: "GET /api/v1/folders/"
|
||||
---
|
||||
openapi: "GET /api/v1/folders"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Update"
|
||||
openapi: "PATCH /api/v1/folders/{folderName}"
|
||||
---
|
||||
openapi: "PATCH /api/v1/folders/{folderId}"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Create"
|
||||
openapi: "POST /api/v1/identities/"
|
||||
---
|
||||
openapi: "POST /api/v1/identities"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Delete"
|
||||
openapi: "DELETE /api/v1/identities/{identityId}"
|
||||
---
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Update"
|
||||
openapi: "PATCH /api/v1/identities/{identityId}"
|
||||
---
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "List Identity Memberships"
|
||||
openapi: "GET /api/v2/organizations/{organizationId}/identity-memberships"
|
||||
---
|
||||
openapi: "GET /api/v2/organizations/{orgId}/identity-memberships"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Create"
|
||||
openapi: "POST /api/v1/secret-imports/"
|
||||
---
|
||||
openapi: "POST /api/v1/secret-imports"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Delete"
|
||||
openapi: "DELETE /api/v1/secret-imports/{id}"
|
||||
---
|
||||
openapi: "DELETE /api/v1/secret-imports/{secretImportId}"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "List"
|
||||
openapi: "GET /api/v1/secret-imports/"
|
||||
---
|
||||
openapi: "GET /api/v1/secret-imports"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Update"
|
||||
openapi: "PUT /api/v1/secret-imports/{id}"
|
||||
---
|
||||
openapi: "PATCH /api/v1/secret-imports/{secretImportId}"
|
||||
---
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: "Get"
|
||||
openapi: "GET /api/v2/service-token/"
|
||||
openapi: "GET /api/v2/service-token"
|
||||
---
|
||||
|
||||
<Warning>
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Delete Identity Membership"
|
||||
openapi: "DELETE /api/v2/workspace/{workspaceId}/identity-memberships/{identityId}"
|
||||
---
|
||||
openapi: "DELETE /api/v2/workspace/{projectId}/identity-memberships/{identityId}"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Delete User Membership"
|
||||
openapi: "DELETE /api/v2/workspace/{workspaceId}/memberships/{membershipId}"
|
||||
openapi: "DELETE /api/v1/workspace/{workspaceId}/memberships/{membershipId}"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "List Identity Memberships"
|
||||
openapi: "GET /api/v2/workspace/{workspaceId}/identity-memberships"
|
||||
---
|
||||
openapi: "GET /api/v2/workspace/{projectId}/identity-memberships"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Get User Memberships"
|
||||
openapi: "GET /api/v2/workspace/{workspaceId}/memberships"
|
||||
openapi: "GET /api/v1/workspace/{workspaceId}/memberships"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Roll Back to Snapshot"
|
||||
openapi: "POST /api/v1/workspace/{workspaceId}/secret-snapshots/rollback"
|
||||
openapi: "POST /api/v1/secret-snapshot/{secretSnapshotId}/rollback"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Update Identity Membership"
|
||||
openapi: "PATCH /api/v2/workspace/{workspaceId}/identity-memberships/{identityId}"
|
||||
---
|
||||
openapi: "PATCH /api/v2/workspace/{projectId}/identity-memberships/{identityId}"
|
||||
---
|
||||
|
@ -1,4 +1,4 @@
|
||||
---
|
||||
title: "Update User Membership"
|
||||
openapi: "PATCH /api/v2/workspace/{workspaceId}/memberships/{membershipId}"
|
||||
openapi: "PATCH /api/v1/workspace/{workspaceId}/memberships/{membershipId}"
|
||||
---
|
||||
|
82
docs/contributing/platform/backend/folder-structure.mdx
Normal file
82
docs/contributing/platform/backend/folder-structure.mdx
Normal file
@ -0,0 +1,82 @@
|
||||
---
|
||||
title: 'Backend folder structure'
|
||||
---
|
||||
|
||||
```
|
||||
├── scripts
|
||||
├── e2e-test
|
||||
└── src/
|
||||
├── @types/
|
||||
│ ├── knex.d.ts
|
||||
│ └── fastify.d.ts
|
||||
├── db/
|
||||
│ ├── migrations
|
||||
│ ├── schemas
|
||||
│ └── seed
|
||||
├── lib/
|
||||
│ ├── fn
|
||||
│ ├── date
|
||||
│ └── config
|
||||
├── queue
|
||||
├── server/
|
||||
│ ├── routes/
|
||||
│ │ ├── v1
|
||||
│ │ └── v2
|
||||
│ ├── plugins
|
||||
│ └── config
|
||||
├── services/
|
||||
│ ├── auth
|
||||
│ ├── org
|
||||
│ └── project/
|
||||
│ ├── project-service.ts
|
||||
│ ├── project-types.ts
|
||||
│ └── project-dal.ts
|
||||
└── ee/
|
||||
├── routes
|
||||
└── services
|
||||
```
|
||||
|
||||
### `backend/scripts`
|
||||
Contains reusable scripts for backend automation, like running migrations and generating SQL schemas.
|
||||
|
||||
### `backend/e2e-test`
|
||||
Integration tests for the APIs.
|
||||
|
||||
### `backend/src`
|
||||
The source code of the backend.
|
||||
|
||||
- `@types`: Type definitions for libraries like Fastify and Knex.
|
||||
- `db`: Knex.js configuration for the database, including migration, seed files, and SQL type schemas.
|
||||
- `lib`: Stateless, reusable functions used across the codebase.
|
||||
- `queue`: Infisical's queue system based on BullMQ.
|
||||
|
||||
### `src/server`
|
||||
|
||||
- Scope anything related to Fastify/service here.
|
||||
- Includes routes, Fastify plugins, and server configurations.
|
||||
- The routes folder contains various versions of routes separated into v1, v2, etc.
|
||||
|
||||
### `src/services`
|
||||
|
||||
- Handles the core business logic for all operations.
|
||||
- Follows the co-location principle: related components should be kept together.
|
||||
- Each service component typically contains:
|
||||
|
||||
1. **dal**: Database Access Layer functions for database operations
|
||||
2. **service**: The service layer containing business logic.
|
||||
3. **type**: Type definitions used within the service component.
|
||||
4. **fns**: An optional component for sharing reusable functions related to the service.
|
||||
5. **queue**: An optional component for queue-specific logic, like `secret-queue.ts`.
|
||||
|
||||
### `src/ee`
|
||||
|
||||
Follows the same pattern as above, with the exception of a license change from MIT to Infisical Proprietary License.
|
||||
|
||||
### Guidelines and Best Practices
|
||||
|
||||
- All services are interconnected at `/src/server/routes/index.ts`, following the principle of simple dependency injection.
|
||||
- Files should be named in dash-case.
|
||||
- Avoid using classes in the codebase; opt for simple functions instead.
|
||||
- All committed code must be properly linted using `npm run lint:fix` and type-checked with `npm run type:check`.
|
||||
- Minimize shared logic between services as much as possible.
|
||||
- Controllers within a router component should ideally call only one service layer, with exceptions for services like `audit-log` that require access to request object data.
|
@ -0,0 +1,56 @@
|
||||
---
|
||||
title: "Backend development guide"
|
||||
---
|
||||
|
||||
Suppose you're interested in implementing a new feature in Infisical's backend, let's call it "feature-x." Here are the general steps you should follow.
|
||||
|
||||
## Database schema migration
|
||||
In order to run [schema migrations](https://en.wikipedia.org/wiki/Schema_migration#:~:text=A%20schema%20migration%20is%20performed,some%20newer%20or%20older%20version) you need to expose your database connection string. Create a `.env.migration` file to set the database connection URI for migration scripts, or alternatively, export the `DB_CONNECTION_URI` environment variable.
|
||||
|
||||
## Creating new database model
|
||||
If your feature involves a change in the database, you need to first address this by generating the necessary database schemas.
|
||||
|
||||
1. If you're adding a new table, update the `TableName` enum in `/src/db/schemas/models.ts` to include the new table name.
|
||||
2. Create a new migration file by running `npm run migration:new` and give it a relevant name, such as `feature-x`.
|
||||
3. Navigate to `/src/db/migrations/<timestamp>_<feature-x>.ts`.
|
||||
4. Modify both the `up` and `down` functions to create or alter Postgres fields on migration up and to revert these changes on migration down, ensuring idempotency as outlined [here](https://github.com/graphile/migrate/blob/main/docs/idempotent-examples.md).
|
||||
|
||||
### Generating TS Schemas
|
||||
|
||||
While typically you would need to manually write TS types for Knex type-sense, we have automated this process:
|
||||
|
||||
1. Start the server.
|
||||
2. Run `npm run migration:latest` to apply all database changes.
|
||||
3. Execute `npm run generate:schema` to automatically generate types and schemas using [zod](https://github.com/colinhacks/zod) in the `/src/db/schemas` folder.
|
||||
4. Update the barrel export in `schema/index` and include the new tables in `/src/@types/knex.d.ts` to enable type-sensing in Knex.js.
|
||||
|
||||
## Business Logic
|
||||
|
||||
Once the database changes are in place, it's time to create the APIs for `feature-x`:
|
||||
|
||||
1. Execute `npm run generate:component`.
|
||||
2. Choose option 1 for the service component.
|
||||
3. Name the service in dash-case, like `feature-x`. This will create a `feature-x` folder in `/src/services` containing three files.
|
||||
1. `feature-x-dal`: The Database Access Layer functions.
|
||||
2. `feature-x-service`: The service layer where all the business logic is handled.
|
||||
3. `feature-x-type`: The types used by `feature-x`.
|
||||
|
||||
For reusable shared functions, set up a file named `feature-x-fns`.
|
||||
|
||||
Use the custom Infisical function `ormify` in `src/lib/knex` for simple database operations within the DAL.
|
||||
|
||||
## Connecting the Service Layer to the Server Layer
|
||||
|
||||
Server-related logic is handled in `/src/server`. To connect the service layer to the server layer, we use Fastify plugins for dependency injection:
|
||||
|
||||
1. Add the service type in the `fastify.d.ts` file under the `service` namespace of a FastifyServerInstance type.
|
||||
2. In `/src/server/routes/index.ts`, instantiate the required dependencies for `feature-x`, such as the DAL and service layers, and then pass them to `fastify.register("service,{...dependencies})`.
|
||||
3. This makes the service layer accessible within all routes under the Fastify service instance, accessed via `server.services.<registered service name>.<function>`.
|
||||
|
||||
## Writing API Routes
|
||||
|
||||
1. To create a route component, run `npm generate:component`.
|
||||
2. Select option 3, type the router name in dash-case, and provide the version number. This will generate a router file in `src/server/routes/v<version-number>/<router component name>`
|
||||
1. Implement your logic to connect with the service layer as needed.
|
||||
2. Import the router component in the version folder's index.ts. For instance, if it's in v1, import it in `v1/index.ts`.
|
||||
3. Finally, register it under the appropriate prefix for access.
|
@ -4,7 +4,7 @@ description: "Programmatically interact with Infisical"
|
||||
---
|
||||
|
||||
<Note>
|
||||
Currently, identities can only be used to make authenticated requests to the Infisical API and SDKs. They do not work with clients such as CLI, K8s Operator, Terraform Provider, etc.
|
||||
Currently, identities can only be used to make authenticated requests to the Infisical API, SDKs, and Agent. They do not work with clients such as CLI, K8s Operator, Terraform Provider, etc.
|
||||
|
||||
We will be releasing compatibility with it across clients in the coming quarter.
|
||||
</Note>
|
||||
@ -50,4 +50,4 @@ Check out the following authentication method-specific guides for step-by-step i
|
||||
- The identity you are trying to read, update, or delete is more privileged than yourself.
|
||||
- The role you are trying to create an identity for or update an identity to is more privileged than yours.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
</AccordionGroup>
|
||||
|
@ -5,6 +5,19 @@ description: "How to use Infisical for secret management in Ansible"
|
||||
|
||||
The documentation for using Infisical to manage secrets in Ansible is currently available [here](https://galaxy.ansible.com/ui/repo/published/infisical/vault/).
|
||||
|
||||
<Info>
|
||||
Have any questions? Join Infisical's [community Slack](https://infisical.com/slack) for quick support.
|
||||
</Info>
|
||||
## Troubleshoot
|
||||
|
||||
<Accordion title="I'm getting a error related to objc[72832]: +[__NSCFConstantString initialize]">
|
||||
If you get this Python error when you running the lookup plugin:-
|
||||
|
||||
```
|
||||
objc[72832]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.
|
||||
Fatal Python error: Aborted
|
||||
```
|
||||
|
||||
You will need to add this to your shell environment or ansible wrapper script:-
|
||||
|
||||
```
|
||||
export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
|
||||
```
|
||||
</Accordion>
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"name": "Infisical",
|
||||
"openapi": "https://app.infisical.com/api/docs/json",
|
||||
"logo": {
|
||||
"dark": "/logo/dark.svg",
|
||||
"light": "/logo/light.svg",
|
||||
@ -463,7 +464,9 @@
|
||||
{
|
||||
"group": "Contributing to platform",
|
||||
"pages": [
|
||||
"contributing/platform/developing"
|
||||
"contributing/platform/developing",
|
||||
"contributing/platform/backend/how-to-create-a-feature",
|
||||
"contributing/platform/backend/folder-structure"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -18,8 +18,8 @@ Other environment variables are listed below to increase the functionality of yo
|
||||
Must be a random 32 byte base64 string. Can be generated with `openssl rand -base64 32`
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="MONGO_URL" type="string" default="none" required>
|
||||
Mongo connection string. *TLS based connection string is not yet supported
|
||||
<ParamField query="DB_CONNECTION_URI" type="string" default="none" required>
|
||||
Postgres database connection string.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="REDIS_URL" type="string" default="none" required>
|
||||
|
@ -2,53 +2,79 @@
|
||||
title: "Docker Compose"
|
||||
description: "Run Infisical with Docker Compose template"
|
||||
---
|
||||
Install Infisical using Docker compose. This self hosting method contains all of the required components needed
|
||||
to run a functional instance of Infisical.
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Docker on your VM">
|
||||
```bash
|
||||
# Example in ubuntu
|
||||
apt-get update
|
||||
apt-get upgrade
|
||||
apt install docker-compose
|
||||
```
|
||||
</Step>
|
||||
<Step title="Download required files">
|
||||
2.1. Run the command below to download the `.env` file template.
|
||||
|
||||
```bash
|
||||
wget -O .env https://raw.githubusercontent.com/Infisical/infisical/main/.env.example
|
||||
```
|
||||
|
||||
2.2. Run the command below to download the docker compose template.
|
||||
|
||||
```bash
|
||||
wget -O docker-compose.yml https://raw.githubusercontent.com/Infisical/infisical/main/docker-compose.yml
|
||||
```
|
||||
|
||||
2.3. Run the command below to download the `nginx` config file.
|
||||
|
||||
```bash
|
||||
mkdir nginx && wget -O ./nginx/default.conf https://raw.githubusercontent.com/Infisical/infisical/main/nginx/default.dev.conf
|
||||
```
|
||||
|
||||
</Step>
|
||||
<Step title="Update the .env file">
|
||||
Running Infisical requires a few environment variables to be set.
|
||||
At minimum, Infisical requires that you set the variables `ENCRYPTION_KEY`, `AUTH_SECRET`, `MONGO_URL`, and `REDIS_URL` which you can read more about [here](/self-hosting/configuration/envars).
|
||||
## Prerequisites
|
||||
- [Docker](https://docs.docker.com/engine/install/)
|
||||
- [Docker compose](https://docs.docker.com/compose/install/)
|
||||
|
||||
Tweak the `.env` accordingly.
|
||||
<Warning>
|
||||
This Docker Compose configuration is not designed for high-availability production scenarios.
|
||||
It includes just the essential components needed to set up an Infisical proof of concept (POC).
|
||||
Additional configuration is required to enhance data redundancy and ensure higher availability for production environments.
|
||||
</Warning>
|
||||
|
||||
```bash
|
||||
nano .env
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start Infisical">
|
||||
Finally, run the command below to get Infisical up and running (in detached mode).
|
||||
## Verify prerequisites
|
||||
To verify that Docker compose and Docker are installed on the machine where you plan to install Infisical, run the following commands.
|
||||
|
||||
Check for docker installation
|
||||
```bash
|
||||
docker-compose -f docker-compose.yml up -d
|
||||
docker
|
||||
```
|
||||
|
||||
Your Infisical installation is complete and should be running on port `80` or `http://localhost:80`.
|
||||
</Step>
|
||||
</Steps>
|
||||
Check for docker compose installation
|
||||
```bash
|
||||
docker-compose
|
||||
```
|
||||
|
||||
## Download docker compose file
|
||||
You can obtain the Infisical docker compose file by using a command-line downloader such as `wget` or `curl`.
|
||||
If your system doesn't have either of these, you can use a equivalent command that works with your machine.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="curl">
|
||||
```bash
|
||||
curl -o docker-compose.prod.yml https://raw.githubusercontent.com/Infisical/infisical/main/docker-compose.prod.yml
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="wget">
|
||||
```bash
|
||||
wget -O docker-compose.prod.yml https://raw.githubusercontent.com/Infisical/infisical/main/docker-compose.prod.yml
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Configure instance credentials
|
||||
Infisical requires a set of credentials used for connecting to dependent services such as Postgres, Redis, etc.
|
||||
The default credentials can be downloaded using the one of the commands listed below.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="curl">
|
||||
```bash
|
||||
curl -o .env https://raw.githubusercontent.com/Infisical/infisical/main/.env.example
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="wget">
|
||||
```bash
|
||||
wget -O .env https://raw.githubusercontent.com/Infisical/infisical/main/.env.example
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
Once downloaded, the credentials file will be saved to your working directly as `.env` file.
|
||||
View all available configurations [here](/self-hosting/configuration/envars).
|
||||
|
||||
<Warning>
|
||||
The default .env file contains credentials that are intended solely for testing purposes.
|
||||
For production use, please generate a new `ENCRYPTION_KEY` and `AUTH_SECRET`. Instructions to do so, can be found [here](/self-hosting/configuration/envars)
|
||||
</Warning>
|
||||
|
||||
## Start Infisical
|
||||
Run the command below to start Infisical and all related services.
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.prod.yml up
|
||||
```
|
||||
|
||||
Your Infisical instance should now be running on port `80`. To access your instance, visit `http://localhost:80`.
|
5152
docs/spec.yaml
5152
docs/spec.yaml
File diff suppressed because it is too large
Load Diff
@ -58,8 +58,8 @@ export default function DonwloadBackupPDFStep({
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center w-full h-full md:px-6 mx-auto mb-36 md:mb-16">
|
||||
<p className="text-xl text-center font-medium flex justify-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
|
||||
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-3 pt-1 text-2xl text-bunker-200" />
|
||||
<p className="text-xl text-center font-medium flex flex-col justify-center items-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
|
||||
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-3 pt-1 mb-6 text-6xl text-bunker-200" />
|
||||
{t("signup.step4-message")}
|
||||
</p>
|
||||
<div className="flex flex-col pb-2 bg-mineshaft-800 border border-mineshaft-600 items-center justify-center text-center lg:w-1/6 w-full md:min-w-[24rem] mt-8 max-w-md text-bunker-300 text-md rounded-md">
|
||||
|
@ -170,7 +170,11 @@ export const AddAPIKeyModal = ({
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
<Button colorSchema="secondary" variant="plain">
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
variant="plain"
|
||||
onClick={() => handlePopUpToggle("addAPIKey", false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -139,7 +139,7 @@ export const WebhooksTab = withProjectPermission(
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-6 max-w-screen-lg rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="flex justify-between">
|
||||
<p className="text-xl font-semibold text-mineshaft-100">{t("settings.webhooks.title")}</p>
|
||||
<ProjectPermissionCan
|
||||
|
@ -128,10 +128,10 @@ export const SignUpPage = () => {
|
||||
animate={{ opacity: 1, translateX: 0 }}
|
||||
exit={{ opacity: 0, translateX: 30 }}
|
||||
>
|
||||
<div className="flex flex-col items-center space-y-4 text-center">
|
||||
<div className="flex flex-col items-center space-y-2 text-center">
|
||||
<img src="/images/gradientLogo.svg" height={90} width={120} alt="Infisical logo" />
|
||||
<div className="text-4xl">Welcome to Infisical</div>
|
||||
<div>Create your first Admin Account</div>
|
||||
<div className="text-4xl pt-4">Welcome to Infisical</div>
|
||||
<div className="text-bunker-300 pb-4">Create your first Super Admin Account</div>
|
||||
</div>
|
||||
<form onSubmit={handleSubmit(handleFormSubmit)}>
|
||||
<div className="mt-8">
|
||||
@ -145,7 +145,7 @@ export const SignUpPage = () => {
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Input isFullWidth size="lg" {...field} />
|
||||
<Input isFullWidth size="md" {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
@ -158,7 +158,7 @@ export const SignUpPage = () => {
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Input isFullWidth size="lg" {...field} />
|
||||
<Input isFullWidth size="md" {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
@ -168,7 +168,7 @@ export const SignUpPage = () => {
|
||||
name="email"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl label="Email" errorText={error?.message} isError={Boolean(error)}>
|
||||
<Input isFullWidth size="lg" {...field} />
|
||||
<Input isFullWidth size="md" {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
@ -181,7 +181,7 @@ export const SignUpPage = () => {
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Input isFullWidth size="lg" type="password" {...field} />
|
||||
<Input isFullWidth size="md" type="password" {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
@ -194,13 +194,13 @@ export const SignUpPage = () => {
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Input isFullWidth size="lg" type="password" {...field} />
|
||||
<Input isFullWidth size="md" type="password" {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Button type="submit" isFullWidth className="mt-4" isLoading={isSubmitting}>
|
||||
Let's Go
|
||||
<Button type="submit" colorSchema="primary" variant="outline_bg" isFullWidth className="mt-4" isLoading={isSubmitting}>
|
||||
Continue
|
||||
</Button>
|
||||
</form>
|
||||
</motion.div>
|
||||
|
@ -15,8 +15,8 @@ export const DownloadBackupKeys = ({ onGenerate }: Props): JSX.Element => {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center w-full h-full md:px-6 mx-auto mb-36 md:mb-16">
|
||||
<p className="text-xl text-center font-medium flex justify-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
|
||||
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-3 pt-1 text-2xl text-bunker-200" />
|
||||
<p className="text-xl text-center font-medium flex flex-col justify-center items-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
|
||||
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-3 pt-1 mb-6 text-6xl text-bunker-200" />
|
||||
{t("signup.step4-message")}
|
||||
</p>
|
||||
<div className="flex flex-col pb-2 bg-mineshaft-800 border border-mineshaft-600 items-center justify-center text-center lg:w-1/6 w-full md:min-w-[24rem] mt-8 max-w-md text-bunker-300 text-md rounded-md">
|
||||
|
Reference in New Issue
Block a user