diff --git a/backend/backend/graphene/types.py b/backend/backend/graphene/types.py index bcd865c1..f6144b26 100644 --- a/backend/backend/graphene/types.py +++ b/backend/backend/graphene/types.py @@ -100,6 +100,22 @@ class Meta: fields = ('id', 'name', 'env_type', 'identity_key', 'wrapped_seed', 'wrapped_salt', 'created_at', 'updated_at') + def resolve_wrapped_seed(self, info): + org_member = OrganisationMember.objects.get( + user=info.context.user, organisation=self.app.organisation, deleted_at=None) + user_env_key = EnvironmentKey.objects.get( + environment=self, user=org_member, deleted_at=None) + + return user_env_key.wrapped_seed + + def resolve_wrapped_salt(self, info): + org_member = OrganisationMember.objects.get( + user=info.context.user, organisation=self.app.organisation, deleted_at=None) + user_env_key = EnvironmentKey.objects.get( + environment=self, user=org_member, deleted_at=None) + + return user_env_key.wrapped_salt + class EnvironmentKeyType(DjangoObjectType): class Meta: diff --git a/frontend/components/apps/NewAppDialog.tsx b/frontend/components/apps/NewAppDialog.tsx index 5add1d2d..c0b3527f 100644 --- a/frontend/components/apps/NewAppDialog.tsx +++ b/frontend/components/apps/NewAppDialog.tsx @@ -121,20 +121,23 @@ export default function NewAppDialog(props: { }) } - async function processSecrets( - appId: string, - envType: ApiEnvironmentEnvTypeChoices, - secrets: Array> - ) { - const { data: appEnvsData } = await getAppEnvs({ variables: { appId } }) + /** + * Encrypts a set of secrets for the given env and creates them server-side + * + * @param {EnvironmentType} env - The environment in which the secrets will be created. + * @param {Array>} secrets - An array of secrets to be processed. + * @returns {Promise} A Promise that resolves when the all secrets are encrypted and stored on the server. + * + * @throws {Error} If the specified environment is invalid or if an error occurs during processing. + */ + async function processSecrets(env: EnvironmentType, secrets: Array>) { + const keyring = await validateKeyring(pw) const userKxKeys = { - publicKey: await getUserKxPublicKey(keyring!.publicKey), - privateKey: await getUserKxPrivateKey(keyring!.privateKey), + publicKey: await getUserKxPublicKey(keyring.publicKey), + privateKey: await getUserKxPrivateKey(keyring.privateKey), } - const env = appEnvsData.appEnvironments.find((env: EnvironmentType) => env.envType === envType) - const envSalt = await decryptAsymmetric( env.wrappedSalt, userKxKeys.privateKey, @@ -167,6 +170,12 @@ export default function NewAppDialog(props: { return Promise.all(promises) } + /** + * Handles the creation of example secrets for a given app. Defines the set of example secrets, fetches all envs for this app and handles creation of each set of secrets with the respective envs + * + * @param {string} appId + * @returns {Promise} + */ const createExampleSecrets = async (appId: string) => { const DEV_SECRETS = [ { @@ -253,47 +262,72 @@ export default function NewAppDialog(props: { }, ] - await processSecrets(appId, ApiEnvironmentEnvTypeChoices.Dev, DEV_SECRETS) - await processSecrets(appId, ApiEnvironmentEnvTypeChoices.Staging, STAG_SECRETS) - await processSecrets(appId, ApiEnvironmentEnvTypeChoices.Prod, PROD_SECRETS) - } + const { data: appEnvsData } = await getAppEnvs({ variables: { appId } }) - const initAppEnvs = async (appId: string) => { - const mutationPayload = { - devEnv: await createNewEnv( - appId, - 'Development', - ApiEnvironmentEnvTypeChoices.Dev, - orgAdminsData.organisationAdminsAndSelf + await processSecrets( + appEnvsData.appEnvironments.find( + (env: EnvironmentType) => env.envType === ApiEnvironmentEnvTypeChoices.Dev ), - stagingEnv: await createNewEnv( - appId, - 'Staging', - ApiEnvironmentEnvTypeChoices.Staging, - orgAdminsData.organisationAdminsAndSelf + DEV_SECRETS + ) + await processSecrets( + appEnvsData.appEnvironments.find( + (env: EnvironmentType) => env.envType === ApiEnvironmentEnvTypeChoices.Staging ), - prodEnv: await createNewEnv( - appId, - 'Production', - ApiEnvironmentEnvTypeChoices.Prod, - orgAdminsData.organisationAdminsAndSelf + STAG_SECRETS + ) + await processSecrets( + appEnvsData.appEnvironments.find( + (env: EnvironmentType) => env.envType === ApiEnvironmentEnvTypeChoices.Prod ), - } + PROD_SECRETS + ) + } - await initAppEnvironments({ - variables: { - devEnv: mutationPayload.devEnv.createEnvPayload, - stagingEnv: mutationPayload.stagingEnv.createEnvPayload, - prodEnv: mutationPayload.prodEnv.createEnvPayload, - devAdminKeys: mutationPayload.devEnv.adminKeysPayload, - stagAdminKeys: mutationPayload.stagingEnv.adminKeysPayload, - prodAdminKeys: mutationPayload.prodEnv.adminKeysPayload, - }, - }) + /** + * Initialize application environments for a given application ID. + * + * @param {string} appId - The ID of the application for which environments will be initialized. + * @returns {Promise} A Promise that resolves to `true` when initialization is complete. + * + * @throws {Error} If there are any errors during the environment initialization process. + */ + const initAppEnvs = async (appId: string) => { + return new Promise(async (resolve, reject) => { + const mutationPayload = { + devEnv: await createNewEnv( + appId, + 'Development', + ApiEnvironmentEnvTypeChoices.Dev, + orgAdminsData.organisationAdminsAndSelf + ), + stagingEnv: await createNewEnv( + appId, + 'Staging', + ApiEnvironmentEnvTypeChoices.Staging, + orgAdminsData.organisationAdminsAndSelf + ), + prodEnv: await createNewEnv( + appId, + 'Production', + ApiEnvironmentEnvTypeChoices.Prod, + orgAdminsData.organisationAdminsAndSelf + ), + } - if (createStarters) { - await createExampleSecrets(appId) - } + await initAppEnvironments({ + variables: { + devEnv: mutationPayload.devEnv.createEnvPayload, + stagingEnv: mutationPayload.stagingEnv.createEnvPayload, + prodEnv: mutationPayload.prodEnv.createEnvPayload, + devAdminKeys: mutationPayload.devEnv.adminKeysPayload, + stagAdminKeys: mutationPayload.stagingEnv.adminKeysPayload, + prodAdminKeys: mutationPayload.prodEnv.adminKeysPayload, + }, + }) + + resolve(true) + }) } const handleCreateApp = async () => { @@ -336,7 +370,13 @@ export default function NewAppDialog(props: { ], }) - await initAppEnvs(data.createApp.app.id) + const newAppId = data.createApp.app.id + + await initAppEnvs(newAppId) + + if (createStarters) { + await createExampleSecrets(newAppId) + } setAppSecret(`pss:v${APP_VERSION}:${appToken}:${appKeyShares[0]}:${wrapKey}`) setAppId(`phApp:v${APP_VERSION}:${appKeys.publicKey}`)