@things-factory/auth-base 10.0.7 → 10.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/privilege/privilege-deprecation.d.ts +14 -0
- package/dist-server/service/privilege/privilege-deprecation.js +49 -0
- package/dist-server/service/privilege/privilege-deprecation.js.map +1 -0
- package/dist-server/service/privilege/privilege-directive.js +3 -1
- package/dist-server/service/privilege/privilege-directive.js.map +1 -1
- package/dist-server/service/privilege/privilege-query.d.ts +8 -0
- package/dist-server/service/privilege/privilege-query.js +22 -0
- package/dist-server/service/privilege/privilege-query.js.map +1 -1
- package/dist-server/service/privilege/privilege-rejection.d.ts +15 -0
- package/dist-server/service/privilege/privilege-rejection.js +50 -0
- package/dist-server/service/privilege/privilege-rejection.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/tests/privilege-deprecation.test.ts +65 -0
- package/tests/privilege-rejection.test.ts +72 -0
- package/translations/en.json +2 -0
- package/translations/ja.json +2 -0
- package/translations/ko.json +2 -0
- package/translations/ms.json +2 -0
- package/translations/zh.json +2 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.privilegeRejection = privilegeRejection;
|
|
4
|
+
const graphql_1 = require("graphql");
|
|
5
|
+
/*
|
|
6
|
+
* 권한 거절을 만든다 — **사용자의 말로, 코드와 함께.**
|
|
7
|
+
*
|
|
8
|
+
* ── 왜 따로 있나 ────────────────────────────────────────────────────────────
|
|
9
|
+
* 이 문장은 프레임워크 apollo 링크(`@operato/graphql` 의 ERROR_HANDLER)를 타고 **사용자 얼굴까지** 간다
|
|
10
|
+
* — 자동으로 닫히지 않는 오류 토스트다. 그런데 다른 서버 오류가 모두 `context.t` 로 옮겨진 뒤에도
|
|
11
|
+
* 여기만 영어 한 문장(`Unauthorized! twin:mutation privilege required`)이었다.
|
|
12
|
+
*
|
|
13
|
+
* 지시자 안에 인라인으로 두면 테스트가 닿지 못한다(스키마를 짓고 리졸버를 태워야 한다). 위험한 것은
|
|
14
|
+
* 게이트 판정이 아니라 **문장 만들기**다 — 번역기가 없는 컨텍스트, 키가 없는 언어, 형태에 의존하는
|
|
15
|
+
* 소비처. 그래서 순수 함수로 떼어 둔다.
|
|
16
|
+
*/
|
|
17
|
+
/** 번역이 없으면 영어 문장을 그대로 쓴다. */
|
|
18
|
+
function localized(context, key, params, fallback) {
|
|
19
|
+
const t = typeof context?.t === 'function' ? context.t : null;
|
|
20
|
+
if (!t)
|
|
21
|
+
return fallback;
|
|
22
|
+
let translated;
|
|
23
|
+
try {
|
|
24
|
+
translated = t(key, params);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
/* 번역기가 던지면 오류의 원인이 번역기로 바뀐다 — 거절은 그대로 전달되어야 한다. */
|
|
28
|
+
return fallback;
|
|
29
|
+
}
|
|
30
|
+
/*
|
|
31
|
+
* i18next 는 키를 못 찾으면 **키를 그대로 돌려준다.** 그걸 쓰면 사용자가
|
|
32
|
+
* `error.x privilege required` 를 읽게 되므로 영어 문장으로 되돌린다
|
|
33
|
+
* (같은 대비를 `privilege-query.ts` 의 description 도 한다).
|
|
34
|
+
*/
|
|
35
|
+
return !translated || translated === key ? fallback : translated;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 권한 거절 오류. `code: 'FORBIDDEN'` + `requires` 를 `extensions` 에 담는다.
|
|
39
|
+
*
|
|
40
|
+
* @param context koa 컨텍스트(요청의 언어를 아는 `t` 를 가진다). 없어도 동작한다.
|
|
41
|
+
*/
|
|
42
|
+
function privilegeRejection(context, category, privilege) {
|
|
43
|
+
const named = !!(category && privilege);
|
|
44
|
+
const requires = named ? { category, privilege } : 'ownership';
|
|
45
|
+
const message = named
|
|
46
|
+
? localized(context, 'error.x privilege required', { x: `${category}:${privilege}` }, `unauthorized! ${category}:${privilege} privilege required`)
|
|
47
|
+
: localized(context, 'error.ownership required', {}, 'unauthorized! domain or system ownership required');
|
|
48
|
+
return new graphql_1.GraphQLError(message, { extensions: { code: 'FORBIDDEN', requires } });
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=privilege-rejection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"privilege-rejection.js","sourceRoot":"","sources":["../../../server/service/privilege/privilege-rejection.ts"],"names":[],"mappings":";;AA+CA,gDAcC;AA7DD,qCAAsC;AAEtC;;;;;;;;;;;GAWG;AAEH,6BAA6B;AAC7B,SAAS,SAAS,CAAC,OAAY,EAAE,GAAW,EAAE,MAA8B,EAAE,QAAgB;IAC5F,MAAM,CAAC,GAAG,OAAO,OAAO,EAAE,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC7D,IAAI,CAAC,CAAC;QAAE,OAAO,QAAQ,CAAA;IAEvB,IAAI,UAAkB,CAAA;IACtB,IAAI,CAAC;QACH,UAAU,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,mDAAmD;QACnD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,UAAU,IAAI,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAA;AAClE,CAAC;AAQD;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,OAAY,EAAE,QAAiB,EAAE,SAAkB;IACpF,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,SAAS,CAAC,CAAA;IACvC,MAAM,QAAQ,GAAyB,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,WAAW,CAAA;IAEpF,MAAM,OAAO,GAAG,KAAK;QACnB,CAAC,CAAC,SAAS,CACP,OAAO,EACP,4BAA4B,EAC5B,EAAE,CAAC,EAAE,GAAG,QAAQ,IAAI,SAAS,EAAE,EAAE,EACjC,iBAAiB,QAAQ,IAAI,SAAS,qBAAqB,CAC5D;QACH,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,0BAA0B,EAAE,EAAE,EAAE,mDAAmD,CAAC,CAAA;IAE3G,OAAO,IAAI,sBAAY,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAA;AACnF,CAAC","sourcesContent":["import { GraphQLError } from 'graphql'\n\n/*\n * 권한 거절을 만든다 — **사용자의 말로, 코드와 함께.**\n *\n * ── 왜 따로 있나 ────────────────────────────────────────────────────────────\n * 이 문장은 프레임워크 apollo 링크(`@operato/graphql` 의 ERROR_HANDLER)를 타고 **사용자 얼굴까지** 간다\n * — 자동으로 닫히지 않는 오류 토스트다. 그런데 다른 서버 오류가 모두 `context.t` 로 옮겨진 뒤에도\n * 여기만 영어 한 문장(`Unauthorized! twin:mutation privilege required`)이었다.\n *\n * 지시자 안에 인라인으로 두면 테스트가 닿지 못한다(스키마를 짓고 리졸버를 태워야 한다). 위험한 것은\n * 게이트 판정이 아니라 **문장 만들기**다 — 번역기가 없는 컨텍스트, 키가 없는 언어, 형태에 의존하는\n * 소비처. 그래서 순수 함수로 떼어 둔다.\n */\n\n/** 번역이 없으면 영어 문장을 그대로 쓴다. */\nfunction localized(context: any, key: string, params: Record<string, string>, fallback: string): string {\n const t = typeof context?.t === 'function' ? context.t : null\n if (!t) return fallback\n\n let translated: string\n try {\n translated = t(key, params)\n } catch {\n /* 번역기가 던지면 오류의 원인이 번역기로 바뀐다 — 거절은 그대로 전달되어야 한다. */\n return fallback\n }\n\n /*\n * i18next 는 키를 못 찾으면 **키를 그대로 돌려준다.** 그걸 쓰면 사용자가\n * `error.x privilege required` 를 읽게 되므로 영어 문장으로 되돌린다\n * (같은 대비를 `privilege-query.ts` 의 description 도 한다).\n */\n return !translated || translated === key ? fallback : translated\n}\n\n/**\n * 무엇이 필요했는지 — 화면이 **문장을 다시 파싱하지 않고** 안내를 만들 수 있게 실어 보낸다.\n * 문장 형태에 의존하면 번역하는 순간 깨진다.\n */\nexport type PrivilegeRequirement = { category: string; privilege: string } | 'ownership'\n\n/**\n * 권한 거절 오류. `code: 'FORBIDDEN'` + `requires` 를 `extensions` 에 담는다.\n *\n * @param context koa 컨텍스트(요청의 언어를 아는 `t` 를 가진다). 없어도 동작한다.\n */\nexport function privilegeRejection(context: any, category?: string, privilege?: string): GraphQLError {\n const named = !!(category && privilege)\n const requires: PrivilegeRequirement = named ? { category, privilege } : 'ownership'\n\n const message = named\n ? localized(\n context,\n 'error.x privilege required',\n { x: `${category}:${privilege}` },\n `unauthorized! ${category}:${privilege} privilege required`\n )\n : localized(context, 'error.ownership required', {}, 'unauthorized! domain or system ownership required')\n\n return new GraphQLError(message, { extensions: { code: 'FORBIDDEN', requires } })\n}\n"]}
|