0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-04-07 23:01:25 -05:00

feat(core,schemas): add block domain list (#5234)

This commit is contained in:
wangsijie 2024-01-15 15:45:00 +08:00 committed by GitHub
parent ca24e20f6a
commit cbfd00e673
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 64 additions and 0 deletions

View file

@ -45,6 +45,7 @@ beforeAll(() => {
SystemContext.shared.hostnameProviderConfig = {
zoneId: 'fake_zone_id',
apiToken: '',
blockedDomains: ['blocked.com'],
};
});
@ -70,6 +71,12 @@ describe('addDomain()', () => {
value: mockFallbackOrigin,
});
});
it('should throw for blocked domain', async () => {
await expect(addDomain('hi.blocked.com')).rejects.toMatchError(
new RequestError({ code: 'domain.domain_is_not_allowed' })
);
});
});
describe('syncDomainStatus()', () => {

View file

@ -11,6 +11,7 @@ import {
deleteCustomHostname,
getFallbackOrigin,
} from '#src/utils/cloudflare/index.js';
import { isSubdomainOf } from '#src/utils/domain.js';
import { clearCustomDomainCache } from '#src/utils/tenant.js';
export type DomainLibrary = ReturnType<typeof createDomainLibrary>;
@ -71,6 +72,14 @@ export const createDomainLibrary = (queries: Queries) => {
const { hostnameProviderConfig } = SystemContext.shared;
assertThat(hostnameProviderConfig, 'domain.not_configured');
const { blockedDomains } = hostnameProviderConfig;
assertThat(
!(blockedDomains ?? []).some(
(domain) => hostname === domain || isSubdomainOf(hostname, domain)
),
'domain.domain_is_not_allowed'
);
const [fallbackOrigin, cloudflareData] = await Promise.all([
getFallbackOrigin(hostnameProviderConfig),
createCustomHostname(hostnameProviderConfig, hostname),

View file

@ -0,0 +1,12 @@
import { isSubdomainOf } from './domain.js';
describe('isSubdomainOf()', () => {
it('should return true if the given domain is a subdomain of a domain', () => {
expect(isSubdomainOf('subdomain.domain.com', 'domain.com')).toBe(true);
});
it('should return false if the given domain is not a subdomain of a domain', () => {
expect(isSubdomainOf('subdomain.domain.com', 'domain.org')).toBe(false);
expect(isSubdomainOf('subdomaindomain.com', 'domain.org')).toBe(false);
});
});

View file

@ -0,0 +1,6 @@
/**
* Checks if the given domain is a subdomain of a domain.
*/
export const isSubdomainOf = (subdomain: string, domain: string): boolean => {
return subdomain.endsWith(`.${domain}`);
};

View file

@ -7,6 +7,8 @@ const domain = {
limit_to_one_domain: 'Sie können nur eine benutzerdefinierte Domain haben.',
hostname_already_exists: 'Diese Domain existiert bereits auf unserem Server.',
cloudflare_not_found: 'Hostname in Cloudflare nicht gefunden',
/** UNTRANSLATED */
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -6,6 +6,7 @@ const domain = {
limit_to_one_domain: 'You can only have one custom domain.',
hostname_already_exists: 'This domain already exists in our server.',
cloudflare_not_found: 'Can not find hostname in Cloudflare',
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -6,6 +6,8 @@ const domain = {
limit_to_one_domain: 'Solo puedes tener un dominio personalizado.',
hostname_already_exists: 'Este dominio ya existe en nuestro servidor.',
cloudflare_not_found: 'No se puede encontrar el nombre de host en Cloudflare',
/** UNTRANSLATED */
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -6,6 +6,8 @@ const domain = {
limit_to_one_domain: "Vous ne pouvez avoir qu'un seul domaine personnalisé",
hostname_already_exists: 'Ce domaine existe déjà sur notre serveur.',
cloudflare_not_found: "Impossible de trouver le nom d'hôte dans Cloudflare",
/** UNTRANSLATED */
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -6,6 +6,8 @@ const domain = {
limit_to_one_domain: 'Puoi avere solo un dominio personalizzato.',
hostname_already_exists: 'Questo dominio esiste già nel nostro server.',
cloudflare_not_found: 'Impossibile trovare il nome host in Cloudflare.',
/** UNTRANSLATED */
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -6,6 +6,8 @@ const domain = {
limit_to_one_domain: 'カスタムドメインは1つしか持てません。',
hostname_already_exists: 'サーバーには既にこのドメインが存在しています。',
cloudflare_not_found: 'Cloudflare からホスト名が見つかりませんでした。',
/** UNTRANSLATED */
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -6,6 +6,8 @@ const domain = {
limit_to_one_domain: '하나의 맞춤 도메인만 사용할 수 있습니다.',
hostname_already_exists: '이 도메인은 이미 서버에 존재합니다.',
cloudflare_not_found: 'Cloudflare에서 호스트 이름을 찾을 수 없습니다.',
/** UNTRANSLATED */
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -6,6 +6,8 @@ const domain = {
limit_to_one_domain: 'Możesz mieć tylko jedną niestandardową domenę.',
hostname_already_exists: 'Ta domena już istnieje na naszym serwerze.',
cloudflare_not_found: 'Nie można znaleźć nazwy hosta w Cloudflare',
/** UNTRANSLATED */
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -6,6 +6,8 @@ const domain = {
limit_to_one_domain: 'Você só pode ter um domínio personalizado.',
hostname_already_exists: 'Este domínio já existe em nosso servidor.',
cloudflare_not_found: 'Não é possível encontrar o nome do host no Cloudflare',
/** UNTRANSLATED */
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -6,6 +6,8 @@ const domain = {
limit_to_one_domain: 'Você só pode ter um domínio personalizado.',
hostname_already_exists: 'Este domínio já existe em nosso servidor.',
cloudflare_not_found: 'Não é possível encontrar o nome de host no Cloudflare',
/** UNTRANSLATED */
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -6,6 +6,8 @@ const domain = {
limit_to_one_domain: 'Вы можете использовать только один пользовательский домен.',
hostname_already_exists: 'Этот домен уже существует на нашем сервере.',
cloudflare_not_found: 'Не удается найти имя хоста в Cloudflare',
/** UNTRANSLATED */
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -6,6 +6,8 @@ const domain = {
limit_to_one_domain: 'Sadece bir özel alan adınız olabilir.',
hostname_already_exists: 'Bu alan adı sunucumuzda zaten mevcut.',
cloudflare_not_found: "Cloudflare'da alan adı bulunamadı.",
/** UNTRANSLATED */
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -6,6 +6,8 @@ const domain = {
limit_to_one_domain: '仅限一个自定义域名。',
hostname_already_exists: '该域名在我们的服务器中已存在。',
cloudflare_not_found: '在 Cloudflare 中找不到主机名',
/** UNTRANSLATED */
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -6,6 +6,8 @@ const domain = {
limit_to_one_domain: '您只能擁有一個自定義域名。',
hostname_already_exists: '此域名已存在於我們的伺服器中。',
cloudflare_not_found: '無法在 Cloudflare 中找到主機名',
/** UNTRANSLATED */
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -6,6 +6,8 @@ const domain = {
limit_to_one_domain: '您只能擁有一個自訂網域。',
hostname_already_exists: '此網域名稱已經存在我們的伺服器中。',
cloudflare_not_found: '無法找到 Cloudflare 中的主機名',
/** UNTRANSLATED */
domain_is_not_allowed: 'This domain is not allowed.',
};
export default Object.freeze(domain);

View file

@ -145,6 +145,7 @@ export const demoSocialGuard: Readonly<{
export const hostnameProviderDataGuard = z.object({
zoneId: z.string(),
apiToken: z.string(), // Requires zone permission for "SSL and Certificates Edit"
blockedDomains: z.string().array().optional(), // Optional list of blocked domains
});
export type HostnameProviderData = z.infer<typeof hostnameProviderDataGuard>;