mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-20 09:22:56 +00:00
feat(app-connections): 1Password App Connection
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
export enum OnePassConnectionMethod {
|
||||
ApiToken = "api-token"
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import { AxiosError } from "axios";
|
||||
|
||||
import { request } from "@app/lib/config/request";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { removeTrailingSlash } from "@app/lib/fn";
|
||||
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
|
||||
import { OnePassConnectionMethod } from "./1password-connection-enums";
|
||||
import { TOnePassConnection, TOnePassConnectionConfig, TOnePassVault } from "./1password-connection-types";
|
||||
|
||||
export const getOnePassInstanceUrl = async (config: TOnePassConnectionConfig) => {
|
||||
const instanceUrl = removeTrailingSlash(config.credentials.instanceUrl);
|
||||
|
||||
await blockLocalAndPrivateIpAddresses(instanceUrl);
|
||||
|
||||
return instanceUrl;
|
||||
};
|
||||
|
||||
export const getOnePassConnectionListItem = () => {
|
||||
return {
|
||||
name: "1Password" as const,
|
||||
app: AppConnection.OnePass as const,
|
||||
methods: Object.values(OnePassConnectionMethod) as [OnePassConnectionMethod.ApiToken]
|
||||
};
|
||||
};
|
||||
|
||||
export const validateOnePassConnectionCredentials = async (config: TOnePassConnectionConfig) => {
|
||||
const instanceUrl = await getOnePassInstanceUrl(config);
|
||||
|
||||
const { apiToken } = config.credentials;
|
||||
|
||||
try {
|
||||
await request.get(`${instanceUrl}/v1/vaults`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiToken}`,
|
||||
Accept: "application/json"
|
||||
}
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof AxiosError) {
|
||||
throw new BadRequestError({
|
||||
message: `Failed to validate credentials: ${error.message || "Unknown error"}`
|
||||
});
|
||||
}
|
||||
throw new BadRequestError({
|
||||
message: "Unable to validate connection: verify credentials"
|
||||
});
|
||||
}
|
||||
|
||||
return config.credentials;
|
||||
};
|
||||
|
||||
export const listOnePassVaults = async (appConnection: TOnePassConnection) => {
|
||||
const instanceUrl = await getOnePassInstanceUrl(appConnection);
|
||||
const { apiToken } = appConnection.credentials;
|
||||
|
||||
const resp = await request.get<TOnePassVault[]>(`${instanceUrl}/v1/vaults`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiToken}`,
|
||||
Accept: "application/json"
|
||||
}
|
||||
});
|
||||
|
||||
return resp.data;
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
import z from "zod";
|
||||
|
||||
import { AppConnections } from "@app/lib/api-docs";
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import {
|
||||
BaseAppConnectionSchema,
|
||||
GenericCreateAppConnectionFieldsSchema,
|
||||
GenericUpdateAppConnectionFieldsSchema
|
||||
} from "@app/services/app-connection/app-connection-schemas";
|
||||
|
||||
import { OnePassConnectionMethod } from "./1password-connection-enums";
|
||||
|
||||
export const OnePassConnectionAccessTokenCredentialsSchema = z.object({
|
||||
apiToken: z.string().trim().min(1, "API Token required").describe(AppConnections.CREDENTIALS.ONEPASS.apiToken),
|
||||
instanceUrl: z
|
||||
.string()
|
||||
.trim()
|
||||
.url("Invalid Connect Server instance URL")
|
||||
.min(1, "Instance URL required")
|
||||
.describe(AppConnections.CREDENTIALS.ONEPASS.instanceUrl)
|
||||
});
|
||||
|
||||
const BaseOnePassConnectionSchema = BaseAppConnectionSchema.extend({ app: z.literal(AppConnection.OnePass) });
|
||||
|
||||
export const OnePassConnectionSchema = BaseOnePassConnectionSchema.extend({
|
||||
method: z.literal(OnePassConnectionMethod.ApiToken),
|
||||
credentials: OnePassConnectionAccessTokenCredentialsSchema
|
||||
});
|
||||
|
||||
export const SanitizedOnePassConnectionSchema = z.discriminatedUnion("method", [
|
||||
BaseOnePassConnectionSchema.extend({
|
||||
method: z.literal(OnePassConnectionMethod.ApiToken),
|
||||
credentials: OnePassConnectionAccessTokenCredentialsSchema.pick({
|
||||
instanceUrl: true
|
||||
})
|
||||
})
|
||||
]);
|
||||
|
||||
export const ValidateOnePassConnectionCredentialsSchema = z.discriminatedUnion("method", [
|
||||
z.object({
|
||||
method: z.literal(OnePassConnectionMethod.ApiToken).describe(AppConnections.CREATE(AppConnection.OnePass).method),
|
||||
credentials: OnePassConnectionAccessTokenCredentialsSchema.describe(
|
||||
AppConnections.CREATE(AppConnection.OnePass).credentials
|
||||
)
|
||||
})
|
||||
]);
|
||||
|
||||
export const CreateOnePassConnectionSchema = ValidateOnePassConnectionCredentialsSchema.and(
|
||||
GenericCreateAppConnectionFieldsSchema(AppConnection.OnePass)
|
||||
);
|
||||
|
||||
export const UpdateOnePassConnectionSchema = z
|
||||
.object({
|
||||
credentials: OnePassConnectionAccessTokenCredentialsSchema.optional().describe(
|
||||
AppConnections.UPDATE(AppConnection.OnePass).credentials
|
||||
)
|
||||
})
|
||||
.and(GenericUpdateAppConnectionFieldsSchema(AppConnection.OnePass));
|
||||
|
||||
export const OnePassConnectionListItemSchema = z.object({
|
||||
name: z.literal("1Password"),
|
||||
app: z.literal(AppConnection.OnePass),
|
||||
methods: z.nativeEnum(OnePassConnectionMethod).array()
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { OrgServiceActor } from "@app/lib/types";
|
||||
|
||||
import { AppConnection } from "../app-connection-enums";
|
||||
import { listOnePassVaults } from "./1password-connection-fns";
|
||||
import { TOnePassConnection } from "./1password-connection-types";
|
||||
|
||||
type TGetAppConnectionFunc = (
|
||||
app: AppConnection,
|
||||
connectionId: string,
|
||||
actor: OrgServiceActor
|
||||
) => Promise<TOnePassConnection>;
|
||||
|
||||
export const onePassConnectionService = (getAppConnection: TGetAppConnectionFunc) => {
|
||||
const listVaults = async (connectionId: string, actor: OrgServiceActor) => {
|
||||
const appConnection = await getAppConnection(AppConnection.OnePass, connectionId, actor);
|
||||
|
||||
try {
|
||||
const vaults = await listOnePassVaults(appConnection);
|
||||
return vaults;
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
listVaults
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
import z from "zod";
|
||||
|
||||
import { DiscriminativePick } from "@app/lib/types";
|
||||
|
||||
import { AppConnection } from "../app-connection-enums";
|
||||
import {
|
||||
CreateOnePassConnectionSchema,
|
||||
OnePassConnectionSchema,
|
||||
ValidateOnePassConnectionCredentialsSchema
|
||||
} from "./1password-connection-schemas";
|
||||
|
||||
export type TOnePassConnection = z.infer<typeof OnePassConnectionSchema>;
|
||||
|
||||
export type TOnePassConnectionInput = z.infer<typeof CreateOnePassConnectionSchema> & {
|
||||
app: AppConnection.OnePass;
|
||||
};
|
||||
|
||||
export type TValidateOnePassConnectionCredentialsSchema = typeof ValidateOnePassConnectionCredentialsSchema;
|
||||
|
||||
export type TOnePassConnectionConfig = DiscriminativePick<TOnePassConnectionInput, "method" | "app" | "credentials"> & {
|
||||
orgId: string;
|
||||
};
|
||||
|
||||
export type TOnePassVault = {
|
||||
id: string;
|
||||
name: string;
|
||||
type: string;
|
||||
items: number;
|
||||
|
||||
attributeVersion: number;
|
||||
contentVersion: number;
|
||||
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./1password-connection-enums";
|
||||
export * from "./1password-connection-fns";
|
||||
export * from "./1password-connection-schemas";
|
||||
export * from "./1password-connection-types";
|
||||
Reference in New Issue
Block a user