Skip to content

Commit

Permalink
fix(console,core,phrases): api resource indicator should be a valid a…
Browse files Browse the repository at this point in the history
…bsolute uri
  • Loading branch information
charIeszhao committed Mar 27, 2024
1 parent affcecd commit 3363a1d
Show file tree
Hide file tree
Showing 35 changed files with 92 additions and 7 deletions.
7 changes: 7 additions & 0 deletions .changeset/hungry-dodos-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@logto/console": patch
"@logto/phrases": patch
"@logto/core": patch
---

fix: api resource indicator must be a valid absolute uri.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isValidUrl } from '@logto/core-kit';
import { type Resource } from '@logto/schemas';
import { useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
Expand Down Expand Up @@ -29,7 +30,7 @@ function CreateForm({ onClose }: Props) {
const {
handleSubmit,
register,
formState: { isSubmitting },
formState: { isSubmitting, errors },
} = useForm<FormData>();

const api = useApi();
Expand Down Expand Up @@ -91,8 +92,13 @@ function CreateForm({ onClose }: Props) {
)}
>
<TextInput
{...register('indicator', { required: true })}
{...register('indicator', {
required: true,
validate: (value) =>
isValidUrl(value) || t('api_resources.invalid_resource_indicator_format'),
})}
placeholder={t('api_resources.api_identifier_placeholder')}
error={errors.indicator?.message}
/>
</FormField>
</form>
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/__mocks__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export const mockResource: Resource = {
tenantId: 'fake_tenant',
id: 'logto_api',
name: 'management api',
indicator: 'logto.dev/api',
indicator: 'https://logto.dev/api',
accessTokenTtl: 3600,
isDefault: false,
};
Expand Down
10 changes: 7 additions & 3 deletions packages/core/src/routes/resource.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe('resource routes', () => {

it('POST /resources', async () => {
const name = 'user api';
const indicator = 'logto.dev/user';
const indicator = 'https://logto.dev/user';
const accessTokenTtl = 60;

const response = await resourceRequest
Expand All @@ -98,7 +98,8 @@ describe('resource routes', () => {

it('POST /resources should throw with invalid input body', async () => {
const name = 'user api';
const indicator = 'logto.dev/user';
const indicator = 'https://logto.dev/user';
const invalidIndicator = 'foo.bar';

await expect(resourceRequest.post('/resources')).resolves.toHaveProperty('status', 400);
await expect(resourceRequest.post('/resources').send({ name })).resolves.toHaveProperty(
Expand All @@ -109,6 +110,9 @@ describe('resource routes', () => {
'status',
400
);
await expect(
resourceRequest.post('/resources').send({ name, indicator: invalidIndicator })
).resolves.toHaveProperty('status', 400);
});

it('POST /resource should throw with duplicated indicator', async () => {
Expand All @@ -132,7 +136,7 @@ describe('resource routes', () => {

it('PATCH /resources/:id', async () => {
const name = 'user api';
const indicator = 'logto.dev/user';
const indicator = 'https://logto.dev/user';
const accessTokenTtl = 60;

const response = await resourceRequest
Expand Down
12 changes: 11 additions & 1 deletion packages/core/src/routes/resource.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isValidUrl } from '@logto/core-kit';
import { isManagementApi, Resources, Scopes } from '@logto/schemas';
import { generateStandardId } from '@logto/shared';
import { yes } from '@silverhand/essentials';
Expand Down Expand Up @@ -82,12 +83,21 @@ export default function resourceRoutes<T extends AuthedRouter>(
// Use the dedicated API `PATCH /resources/:id/is-default` to update.
body: Resources.createGuard.omit({ id: true, isDefault: true }),
response: Resources.guard.extend({ scopes: Scopes.guard.array().optional() }),
status: [201, 422],
status: [201, 400, 422],
}),
async (ctx, next) => {
const { body } = ctx.guard;
const { indicator } = body;

assertThat(
isValidUrl(indicator),
new RequestError({
code: 'resource.invalid_resource_indicator_format',
indicator,
status: 400,
})
);

assertThat(
!(await findResourceByIndicator(indicator)),
new RequestError({
Expand Down
2 changes: 2 additions & 0 deletions packages/phrases/src/locales/de/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const resource = {
resource_identifier_in_use: 'Die API-Kennung {{indicator}} wird bereits verwendet',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
/** UNTRANSLATED */
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const api_resources = {
default_api_label:
'Pro Mandant kann nur eine Standard-API festgelegt werden. Wenn eine Standard-API festgelegt ist, kann der Ressourcenparameter in der Authentifizierungsanfrage weggelassen werden. Folgende Token-Austauschvorgänge verwenden standardmäßig die API als Publikum, was zur Ausgabe von JWTs führt. <a>Erfahren Sie mehr</a>',
api_resource_created: 'Die API-Ressource {{name}} wurde erfolgreich erstellt',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);
1 change: 1 addition & 0 deletions packages/phrases/src/locales/en/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const resource = {
resource_identifier_in_use: 'The API identifier {{indicator}} is already in use',
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const api_resources = {
default_api_label:
'Only zero or one default API can be set per tenant.\nWhen a default API is designated, the resource parameter can be omitted in the auth request. Subsequent token exchanges will use that API as the audience by default, resulting in the issuance of JWTs. <a>Learn more</a>',
api_resource_created: 'The API resource {{name}} has been successfully created',
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);
2 changes: 2 additions & 0 deletions packages/phrases/src/locales/es/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const resource = {
resource_identifier_in_use: '"El identificador de API {{indicator}} ya está en uso',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
/** UNTRANSLATED */
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const api_resources = {
default_api_label:
'Sólo se puede establecer cero o una API por defecto por inquilino. Cuando se designa una API por defecto, el parámetro de recurso se puede omitir en la solicitud de autenticación. Las posteriores intercambios de tokens utilizarán esa API como audiencia por defecto, lo que dará lugar a la emisión de JWTs. <a>Obtener más información</a>',
api_resource_created: 'El recurso de API {{name}} se ha creado correctamente',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);
2 changes: 2 additions & 0 deletions packages/phrases/src/locales/fr/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const resource = {
resource_identifier_in_use: "L'identifiant d'API {{indicator}} est déjà utilisé",
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
/** UNTRANSLATED */
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const api_resources = {
default_api_label:
'Seulement zéro ou une API par défaut peut être définie par tenant. Lorsqu\'une API par défaut est désignée, le paramètre "resource" peut être omis dans la demande d\'authentification. Les échanges de jetons ultérieurs utiliseront cette API comme public cible par défaut, ce qui entraînera la délivrance de JWT. <a>En savoir plus</a>',
api_resource_created: 'La ressource API {{name}} a été créée avec succès.',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);
2 changes: 2 additions & 0 deletions packages/phrases/src/locales/it/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const resource = {
resource_identifier_in_use: "L'identificatore API {{indicator}} è già in uso",
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
/** UNTRANSLATED */
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const api_resources = {
default_api_label:
'Solo zero o una API predefinita possono essere impostate per tenant. Quando viene designata una API predefinita, il parametro di risorsa può essere omesso nella richiesta di autorizzazione. Gli scambi di token successivi utilizzeranno quell API come destinatario per impostazione predefinita, con conseguente rilascio di JWT. <a>Scopri di più</a>',
api_resource_created: 'La risorsa API {{name}} è stata creata con successo',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);
2 changes: 2 additions & 0 deletions packages/phrases/src/locales/ja/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const resource = {
resource_identifier_in_use: 'API識別子 {{indicator}} はすでに使用されています',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
/** UNTRANSLATED */
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const api_resources = {
default_api_label:
'テナントごとにデフォルトのAPIを0または1つだけ設定できます。デフォルトのAPIが指定されている場合、認証リクエストでリソースパラメータを省略できます。その後のトークン交換は、デフォルトのAPIを対象として行われます。それにより、JWTが発行されます。<a>詳細を見る</a>',
api_resource_created: 'APIリソース{{name}}が正常に作成されました',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);
2 changes: 2 additions & 0 deletions packages/phrases/src/locales/ko/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const resource = {
resource_identifier_in_use: 'API 식별자 {{indicator}}가 이미 사용 중입니다',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
/** UNTRANSLATED */
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const api_resources = {
default_api_label:
'테넌트 당 기본 API는 0개 또는 1개만 지정 할 수 있어요. 기본 API가 지정되면 인증 요청에서 리소스 매개 변수를 생략할 수 있어요. 이후 토큰 교환이 기본적으로 대상에 해당하는 API를 사용하여 수행되어 JWT가 발급되어요. <a>자세히 알아보기</a>',
api_resource_created: '{{name}} API 리소스가 성공적으로 생성되었어요.',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);
2 changes: 2 additions & 0 deletions packages/phrases/src/locales/pl-pl/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const resource = {
resource_identifier_in_use: 'Identyfikator API {{indicator}} jest już używany',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
/** UNTRANSLATED */
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const api_resources = {
default_api_label:
'Tylko jedno API domyślne może być ustawione na jeden najem. Kiedy określone zostanie API domyślne, parametr zasobu może zostać pominięty w żądaniu autoryzacji. Następujące procesy wymiany tokenu będą domyślnie korzystać z tego API, co umożliwi wydanie JWT. <a>Dowiedz się więcej</a>',
api_resource_created: 'Zasób API {{name}} został pomyślnie utworzony',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);
2 changes: 2 additions & 0 deletions packages/phrases/src/locales/pt-br/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const resource = {
resource_identifier_in_use: 'O identificador de API {{indicator}} já está em uso',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
/** UNTRANSLATED */
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const api_resources = {
default_api_label:
'Apenas uma API padrão pode ser definida por locatário. Quando uma API padrão é definida, o parâmetro de recurso pode ser omitido na solicitação de autenticação. As trocas de token subsequentes usarão essa API como audiência por padrão, resultando na emissão de JWTs. <a>Saiba mais</a>',
api_resource_created: 'O recurso API {{name}} foi criado com sucesso',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);
2 changes: 2 additions & 0 deletions packages/phrases/src/locales/pt-pt/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const resource = {
resource_identifier_in_use: 'O identificador da API {{indicator}} já está em uso',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
/** UNTRANSLATED */
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const api_resources = {
default_api_label:
'Somente uma API padrão pode ser definida por inquilino. Quando uma API padrão é definida, o parâmetro de recurso pode ser omitido na solicitação de autorização. Subsequentes trocas de token usarão essa API como audiência por padrão, resultando na emissão de JWTs. <a>Saiba mais</a>',
api_resource_created: 'O recurso de API {{name}} foi criado com sucesso',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);
2 changes: 2 additions & 0 deletions packages/phrases/src/locales/ru/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const resource = {
resource_identifier_in_use: 'Идентификатор API {{indicator}} уже используется',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
/** UNTRANSLATED */
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const api_resources = {
default_api_label:
'В каждом арендаторе может быть только один API по умолчанию. Когда устанавливается API по умолчанию, можно опустить параметр <a>resource</a> в запросе на аутентификацию. Последующие запросы на обмен токенами будут использовать указанное API в качестве аудитории по умолчанию, что приведет к выдаче JWT. <a>Узнать больше</a>',
api_resource_created: 'Ресурс API {{name}} был успешно создан',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);
2 changes: 2 additions & 0 deletions packages/phrases/src/locales/tr-tr/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const resource = {
resource_identifier_in_use: 'API tanımlayıcısı {{indicator}} zaten kullanımda',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
/** UNTRANSLATED */
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const api_resources = {
default_api_label:
'Mandant başına sadece sıfır veya bir varsayılan API ayarlanabilir. Varsayılan bir API belirlendiğinde, auth isteğindeki kaynak parametresi çıkarılabilir. Sonraki token değişimlerinde varsayılan olarak bu API hedef alınarak JWTler oluşturulur. <a>Daha fazla bilgi edinin</a>',
api_resource_created: '{{name}} API kaynağı başarıyla oluşturuldu',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);
2 changes: 2 additions & 0 deletions packages/phrases/src/locales/zh-cn/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const resource = {
resource_identifier_in_use: 'API 标识符 {{indicator}} 已被使用',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
/** UNTRANSLATED */
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const api_resources = {
default_api_label:
'每个租户只能设置零个或一个默认 API。当指定默认 API 时,可以在认证请求中省略资源参数。后续令牌交换将默认使用该 API 作为 Audience,从而签发 JWT。<a>了解更多</a>',
api_resource_created: ' API 资源 {{name}} 已成功创建。',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);
2 changes: 2 additions & 0 deletions packages/phrases/src/locales/zh-hk/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const resource = {
resource_identifier_in_use: 'API 識別碼 {{indicator}} 已經被使用',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
/** UNTRANSLATED */
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const api_resources = {
default_api_label:
'一个租户只能设置零或一个默认 API。当指定默认 API 时,可以在身份验证请求中省略资源参数,还可以使用该 API 作为默认受众方进行令牌交换,从而发放 JWT。<a>了解更多</a>',
api_resource_created: ' API 資源 {{name}} 已成功創建。',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);
2 changes: 2 additions & 0 deletions packages/phrases/src/locales/zh-tw/errors/resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const resource = {
resource_identifier_in_use: 'API 識別碼 {{indicator}} 已經被使用',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API resource indicator must be a valid absolute URI.',
/** UNTRANSLATED */
cannot_delete_management_api: 'Cannot delete Logto management API.',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const api_resources = {
default_api_label:
'一個租戶只能設定零個或一個預設 API。當指定了預設 API 後,可以在授權請求中省略 `resource` 參數。隨後的令牌交換將使用該 API 作為默認的 Audience,從而產生 JWT。<a>了解更多</a>',
api_resource_created: ' API 資源 {{name}} 已成功創建。',
/** UNTRANSLATED */
invalid_resource_indicator_format: 'API indicator must be a valid absolute URI.',
};

export default Object.freeze(api_resources);

0 comments on commit 3363a1d

Please sign in to comment.