Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: misc fixes for creating new apps, keyring and example secrets #86

Merged
merged 3 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions backend/backend/graphene/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
132 changes: 86 additions & 46 deletions frontend/components/apps/NewAppDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,20 +121,23 @@ export default function NewAppDialog(props: {
})
}

async function processSecrets(
appId: string,
envType: ApiEnvironmentEnvTypeChoices,
secrets: Array<Partial<SecretType>>
) {
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<Partial<SecretType>>} secrets - An array of secrets to be processed.
* @returns {Promise<void>} 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<Partial<SecretType>>) {
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,
Expand Down Expand Up @@ -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<void>}
*/
const createExampleSecrets = async (appId: string) => {
const DEV_SECRETS = [
{
Expand Down Expand Up @@ -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<boolean>} 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<boolean>(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 () => {
Expand Down Expand Up @@ -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}`)
Expand Down
Loading