0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-02-17 22:04:19 -05:00

feat(core): delete protected app (#5191)

This commit is contained in:
wangsijie 2024-01-11 15:30:42 +08:00 committed by GitHub
parent 5bc649e10d
commit 67be81e6df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 5 deletions

View file

@ -2,10 +2,30 @@ import { EnvSet } from '#src/env-set/index.js';
import type Queries from '#src/tenants/Queries.js';
import SystemContext from '#src/tenants/SystemContext.js';
import assertThat from '#src/utils/assert-that.js';
import { updateProtectedAppSiteConfigs } from '#src/utils/cloudflare/index.js';
import {
deleteProtectedAppSiteConfigs,
updateProtectedAppSiteConfigs,
} from '#src/utils/cloudflare/index.js';
export type ProtectedAppLibrary = ReturnType<typeof createProtectedAppLibrary>;
const getProviderConfig = async () => {
const { protectedAppConfigProviderConfig } = SystemContext.shared;
assertThat(protectedAppConfigProviderConfig, 'application.protected_app_not_configured');
return protectedAppConfigProviderConfig;
};
const deleteRemoteAppConfigs = async (host: string): Promise<void> => {
if (EnvSet.values.isIntegrationTest) {
return;
}
const protectedAppConfigProviderConfig = await getProviderConfig();
await deleteProtectedAppSiteConfigs(protectedAppConfigProviderConfig, host);
};
export const createProtectedAppLibrary = (queries: Queries) => {
const {
applications: { findApplicationById },
@ -17,8 +37,7 @@ export const createProtectedAppLibrary = (queries: Queries) => {
return;
}
const { protectedAppConfigProviderConfig } = SystemContext.shared;
assertThat(protectedAppConfigProviderConfig, 'application.protected_app_not_configured');
const protectedAppConfigProviderConfig = await getProviderConfig();
const { protectedAppMetadata, id, secret } = await findApplicationById(applicationId);
if (!protectedAppMetadata) {
@ -41,5 +60,6 @@ export const createProtectedAppLibrary = (queries: Queries) => {
return {
syncAppConfigsToRemote,
deleteRemoteAppConfigs,
};
};

View file

@ -12,6 +12,7 @@ const { jest } = import.meta;
const findApplicationById = jest.fn(async () => mockApplication);
const deleteApplicationById = jest.fn();
const syncAppConfigsToRemote = jest.fn();
const deleteRemoteAppConfigs = jest.fn();
const updateApplicationById = jest.fn(
async (_, data: Partial<CreateApplication>): Promise<Application> => ({
...mockApplication,
@ -43,7 +44,10 @@ const tenantContext = new MockTenant(
},
},
undefined,
{ quota: createMockQuotaLibrary(), protectedApps: { syncAppConfigsToRemote } }
{
quota: createMockQuotaLibrary(),
protectedApps: { syncAppConfigsToRemote, deleteRemoteAppConfigs },
}
);
const { createRequester } = await import('#src/utils/test-utils.js');
@ -64,6 +68,7 @@ describe('application route', () => {
afterEach(() => {
updateApplicationById.mockClear();
syncAppConfigsToRemote.mockClear();
deleteRemoteAppConfigs.mockClear();
});
const applicationRequest = createRequester({ authedRoutes: applicationRoutes, tenantContext });
@ -303,11 +308,15 @@ describe('application route', () => {
);
});
it('DELETE /applications/:applicationId', async () => {
it('DELETE /applications/:applicationId for protected app', async () => {
findApplicationById.mockResolvedValueOnce(mockProtectedApplication);
await expect(applicationRequest.delete('/applications/foo')).resolves.toHaveProperty(
'status',
204
);
expect(deleteRemoteAppConfigs).toHaveBeenCalledWith(
mockProtectedApplication.protectedAppMetadata?.host
);
});
it('DELETE /applications/:applicationId should throw if application not found', async () => {

View file

@ -306,6 +306,10 @@ export default function applicationRoutes<T extends AuthedRouter>(
}),
async (ctx, next) => {
const { id } = ctx.guard.params;
const { type, protectedAppMetadata } = await findApplicationById(id);
if (type === ApplicationType.Protected && protectedAppMetadata) {
await protectedApps.deleteRemoteAppConfigs(protectedAppMetadata.host);
}
// Note: will need delete cascade when application is joint with other tables
await deleteApplicationById(id);
ctx.status = 204;

View file

@ -54,3 +54,28 @@ export const updateProtectedAppSiteConfigs = async (
handleResponse(response);
};
export const deleteProtectedAppSiteConfigs = async (
auth: ProtectedAppConfigProviderData,
host: string
) => {
const response = await got.delete(
new URL(
path.join(
baseUrl.pathname,
`/accounts/${auth.accountIdentifier}/storage/kv/namespaces/${
auth.namespaceIdentifier
}/values/${encodeURIComponent(`${auth.keyName}:${host}`)}`
),
baseUrl
),
{
headers: {
Authorization: `Bearer ${auth.apiToken}`,
},
throwHttpErrors: false,
}
);
handleResponse(response);
};