scope-utils.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import {
  2. ACTION,
  3. ALL_SIGN,
  4. SCOPE,
  5. type Scope,
  6. } from '@growi/core/dist/interfaces';
  7. export const isValidScope = (scope: Scope): boolean => {
  8. const scopeParts = scope
  9. .split(':')
  10. .map((x) => (x === ALL_SIGN ? 'ALL' : x.toUpperCase()));
  11. let obj: any = SCOPE;
  12. for (const part of scopeParts) {
  13. if (obj[part] == null) {
  14. return false;
  15. }
  16. obj = obj[part];
  17. }
  18. return obj === scope;
  19. };
  20. export const hasAllScope = (scope: Scope): scope is Scope => {
  21. return scope.endsWith(`:${ALL_SIGN}`);
  22. };
  23. /**
  24. * Returns all values of the scope object
  25. * For example, SCOPE.READ.USER_SETTINGS.API.ALL returns ['read:user:api:access_token', 'read:user:api:api_token']
  26. */
  27. const getAllScopeValuesFromObj = (scopeObj: any): Scope[] => {
  28. const result: Scope[] = [];
  29. const traverse = (current: any): void => {
  30. if (typeof current !== 'object' || current === null) {
  31. if (typeof current === 'string') {
  32. result.push(current as Scope);
  33. }
  34. return;
  35. }
  36. Object.values(current).forEach((value) => {
  37. traverse(value);
  38. });
  39. };
  40. traverse(scopeObj);
  41. return result;
  42. };
  43. /**
  44. * Returns all implied scopes for a given scope
  45. * For example, WRITE permission implies READ permission
  46. */
  47. const getImpliedScopes = (scope: Scope): Scope[] => {
  48. const scopeParts = scope.split(':');
  49. if (scopeParts[0] === ACTION.READ) {
  50. return [scope];
  51. }
  52. if (scopeParts[0] === ACTION.WRITE) {
  53. return [scope, `${ACTION.READ}:${scopeParts.slice(1).join(':')}` as Scope];
  54. }
  55. return [];
  56. };
  57. export const extractAllScope = (scope: Scope): Scope[] => {
  58. if (!hasAllScope(scope)) {
  59. return [scope];
  60. }
  61. const result = [] as Scope[];
  62. const scopeParts = scope.split(':').map((x) => x.toUpperCase());
  63. let obj: any = SCOPE;
  64. scopeParts.forEach((part) => {
  65. if (part === ALL_SIGN) {
  66. return;
  67. }
  68. obj = obj[part];
  69. });
  70. getAllScopeValuesFromObj(obj).forEach((value) => {
  71. result.push(value);
  72. });
  73. return result.filter((scope) => !hasAllScope(scope));
  74. };
  75. /**
  76. * Extracts scopes from a given array of scopes
  77. * And delete all scopes
  78. * For example, [SCOPE.WRITE.USER_SETTINGS.API.ALL] === ['write:user:api:all']
  79. * returns ['read:user:api:access_token',
  80. * 'read:user:api:api_token'
  81. * 'write:user:api:access_token',
  82. * 'write:user:api:api_token']
  83. */
  84. export const extractScopes = (scopes?: Scope[]): Scope[] => {
  85. if (scopes == null) {
  86. return [];
  87. }
  88. const result = new Set<Scope>(); // remove duplicates
  89. const impliedScopes = new Set<Scope>();
  90. scopes.forEach((scope) => {
  91. getImpliedScopes(scope).forEach((impliedScope) => {
  92. impliedScopes.add(impliedScope);
  93. });
  94. });
  95. impliedScopes.forEach((scope) => {
  96. extractAllScope(scope).forEach((extractedScope) => {
  97. result.add(extractedScope);
  98. });
  99. });
  100. return Array.from(result);
  101. };