@cedarjs/cli 8.0.0-canary.3538 → 8.0.0-canary.3540
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/commands/generate/realtime/realtimeHandler.js +13 -5
- package/dist/commands/generate/sdl/sdlHandler.js +10 -2
- package/dist/commands/setup/realtime/realtimeHandler.js +43 -18
- package/dist/commands/setup/tenancy/authCodemod.js +181 -16
- package/dist/commands/setup/tenancy/authDirectives.js +101 -0
- package/dist/commands/setup/tenancy/permissionsPackage.js +240 -0
- package/dist/commands/setup/tenancy/templates/OrgScope.tsx.template +40 -1
- package/dist/commands/setup/tenancy/templates/organizations.sdl.ts.template +8 -6
- package/dist/commands/setup/tenancy/templates/organizations.test.ts.template +24 -28
- package/dist/commands/setup/tenancy/templates/organizations.ts.template +6 -6
- package/dist/commands/setup/tenancy/templates/permissions.ts.template +20 -0
- package/dist/commands/setup/tenancy/templates/permissionsPackage.index.ts.template +28 -0
- package/dist/commands/setup/tenancy/templates/requireOrgAuth.test.ts.template +56 -0
- package/dist/commands/setup/tenancy/templates/requireOrgAuth.ts.template +25 -0
- package/dist/commands/setup/tenancy/templates/requirePermission.test.ts.template +50 -0
- package/dist/commands/setup/tenancy/templates/requirePermission.ts.template +32 -0
- package/dist/commands/setup/tenancy/templates/requireUserAuth.test.ts.template +26 -0
- package/dist/commands/setup/tenancy/templates/requireUserAuth.ts.template +26 -0
- package/dist/commands/setup/tenancy/tenancyHandler.js +127 -13
- package/dist/commands/setup/tenancy/webHasRole.js +45 -0
- package/dist/commands/setup/uploads/uploadsHandler.js +4 -0
- package/dist/lib/authDirective.js +37 -0
- package/package.json +13 -13
- package/dist/commands/setup/tenancy/templates/requireMembership.test.ts.template +0 -35
- package/dist/commands/setup/tenancy/templates/requireMembership.ts.template +0 -25
|
@@ -7,6 +7,7 @@ import prompts from "prompts";
|
|
|
7
7
|
import { colors as c } from "@cedarjs/cli-helpers/colors";
|
|
8
8
|
import { generate as generateTypes } from "@cedarjs/internal/dist/generate/generate";
|
|
9
9
|
import { errorTelemetry } from "@cedarjs/telemetry";
|
|
10
|
+
import { withAuthDirective } from "../../../lib/authDirective.js";
|
|
10
11
|
import {
|
|
11
12
|
generateTemplate,
|
|
12
13
|
getPaths,
|
|
@@ -119,14 +120,18 @@ async function handler({
|
|
|
119
120
|
exampleFile,
|
|
120
121
|
exampleSubscriptionTemplateContent
|
|
121
122
|
);
|
|
122
|
-
const blankTemplateContent =
|
|
123
|
-
setupScriptContent,
|
|
124
|
-
|
|
123
|
+
const blankTemplateContent = withAuthDirective(
|
|
124
|
+
await generateTemplate(setupScriptContent, templateVariables(name)),
|
|
125
|
+
// Not about a model, so the safe default
|
|
126
|
+
{ belongsToOrg: true }
|
|
125
127
|
);
|
|
126
128
|
return [
|
|
127
129
|
writeFile(
|
|
128
130
|
sdlFile,
|
|
129
|
-
|
|
131
|
+
withAuthDirective(
|
|
132
|
+
await generateTemplate(sdlContent, templateVariables(name)),
|
|
133
|
+
{ belongsToOrg: true }
|
|
134
|
+
),
|
|
130
135
|
{
|
|
131
136
|
overwriteExisting: force
|
|
132
137
|
}
|
|
@@ -176,7 +181,10 @@ async function handler({
|
|
|
176
181
|
return [
|
|
177
182
|
writeFile(
|
|
178
183
|
sdlFile,
|
|
179
|
-
|
|
184
|
+
withAuthDirective(
|
|
185
|
+
await generateTemplate(sdlContent, templateVariables(name)),
|
|
186
|
+
{ belongsToOrg: true }
|
|
187
|
+
),
|
|
180
188
|
{
|
|
181
189
|
overwriteExisting: force
|
|
182
190
|
}
|
|
@@ -9,6 +9,10 @@ import { generate as generateTypes } from "@cedarjs/internal/dist/generate/gener
|
|
|
9
9
|
import { getConfig } from "@cedarjs/project-config";
|
|
10
10
|
import { errorTelemetry } from "@cedarjs/telemetry";
|
|
11
11
|
import { pluralize } from "@cedarjs/utils/cedarPluralize";
|
|
12
|
+
import {
|
|
13
|
+
belongsToOrganization,
|
|
14
|
+
withAuthDirective
|
|
15
|
+
} from "../../../lib/authDirective.js";
|
|
12
16
|
import { transformTSToJS } from "../../../lib/index.js";
|
|
13
17
|
import {
|
|
14
18
|
prepareForRollback,
|
|
@@ -159,7 +163,8 @@ const sdlFromSchemaModel = async (name, crud, docs = false) => {
|
|
|
159
163
|
idType: idType(model, crud),
|
|
160
164
|
idName: idName(model, crud),
|
|
161
165
|
relations: relationsForModel(model),
|
|
162
|
-
enums
|
|
166
|
+
enums,
|
|
167
|
+
belongsToOrg: belongsToOrganization(model)
|
|
163
168
|
};
|
|
164
169
|
};
|
|
165
170
|
const files = async ({
|
|
@@ -180,7 +185,10 @@ const files = async ({
|
|
|
180
185
|
templateVars: { docs, name, crud, ...sdlData },
|
|
181
186
|
outputPath: `${camelcase(pluralize(name))}.sdl.${extension}`
|
|
182
187
|
});
|
|
183
|
-
const
|
|
188
|
+
const sdl = withAuthDirective(content, {
|
|
189
|
+
belongsToOrg: sdlData.belongsToOrg
|
|
190
|
+
});
|
|
191
|
+
const template = typescript ? sdl : await transformTSToJS(outputPath, sdl);
|
|
184
192
|
return {
|
|
185
193
|
[outputPath]: template,
|
|
186
194
|
...await serviceFiles({
|
|
@@ -7,6 +7,7 @@ import { addApiPackages } from "@cedarjs/cli-helpers/installHelpers";
|
|
|
7
7
|
import { runBinSync } from "@cedarjs/cli-helpers/packageManager/exec";
|
|
8
8
|
import { generate as generateTypes } from "@cedarjs/internal/dist/generate/generate";
|
|
9
9
|
import { errorTelemetry } from "@cedarjs/telemetry";
|
|
10
|
+
import { withAuthDirective } from "../../../lib/authDirective.js";
|
|
10
11
|
import { getPaths, transformTSToJS, writeFile } from "../../../lib/index.js";
|
|
11
12
|
import { isTypeScriptProject, serverFileExists } from "../../../lib/project.js";
|
|
12
13
|
import { setupServerFileTasks } from "../server-file/serverFileHandler.js";
|
|
@@ -97,9 +98,13 @@ async function handler(args) {
|
|
|
97
98
|
exampleSubscriptionTemplateContent
|
|
98
99
|
);
|
|
99
100
|
return [
|
|
100
|
-
writeFile(
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
writeFile(
|
|
102
|
+
exampleFile,
|
|
103
|
+
withAuthDirective(setupScriptContent, { belongsToOrg: false }),
|
|
104
|
+
{
|
|
105
|
+
overwriteExisting: force
|
|
106
|
+
}
|
|
107
|
+
)
|
|
103
108
|
];
|
|
104
109
|
}
|
|
105
110
|
},
|
|
@@ -158,15 +163,23 @@ async function handler(args) {
|
|
|
158
163
|
exampleSubscriptionTemplateContent
|
|
159
164
|
);
|
|
160
165
|
return [
|
|
161
|
-
writeFile(
|
|
162
|
-
|
|
163
|
-
|
|
166
|
+
writeFile(
|
|
167
|
+
sdlFile,
|
|
168
|
+
withAuthDirective(sdlContent, { belongsToOrg: false }),
|
|
169
|
+
{
|
|
170
|
+
overwriteExisting: force
|
|
171
|
+
}
|
|
172
|
+
),
|
|
164
173
|
writeFile(serviceFile, serviceContent, {
|
|
165
174
|
overwriteExisting: force
|
|
166
175
|
}),
|
|
167
|
-
writeFile(
|
|
168
|
-
|
|
169
|
-
|
|
176
|
+
writeFile(
|
|
177
|
+
exampleFile,
|
|
178
|
+
withAuthDirective(setupScriptContent, { belongsToOrg: false }),
|
|
179
|
+
{
|
|
180
|
+
overwriteExisting: force
|
|
181
|
+
}
|
|
182
|
+
)
|
|
170
183
|
];
|
|
171
184
|
}
|
|
172
185
|
},
|
|
@@ -206,9 +219,13 @@ async function handler(args) {
|
|
|
206
219
|
);
|
|
207
220
|
const serviceContent = ts ? exampleServiceTemplateContent : await transformTSToJS(serviceFile, exampleServiceTemplateContent);
|
|
208
221
|
return [
|
|
209
|
-
writeFile(
|
|
210
|
-
|
|
211
|
-
|
|
222
|
+
writeFile(
|
|
223
|
+
sdlFile,
|
|
224
|
+
withAuthDirective(sdlContent, { belongsToOrg: false }),
|
|
225
|
+
{
|
|
226
|
+
overwriteExisting: force
|
|
227
|
+
}
|
|
228
|
+
),
|
|
212
229
|
writeFile(serviceFile, serviceContent, {
|
|
213
230
|
overwriteExisting: force
|
|
214
231
|
})
|
|
@@ -251,9 +268,13 @@ async function handler(args) {
|
|
|
251
268
|
);
|
|
252
269
|
const serviceContent = ts ? exampleServiceTemplateContent : await transformTSToJS(serviceFile, exampleServiceTemplateContent);
|
|
253
270
|
return [
|
|
254
|
-
writeFile(
|
|
255
|
-
|
|
256
|
-
|
|
271
|
+
writeFile(
|
|
272
|
+
sdlFile,
|
|
273
|
+
withAuthDirective(sdlContent, { belongsToOrg: false }),
|
|
274
|
+
{
|
|
275
|
+
overwriteExisting: force
|
|
276
|
+
}
|
|
277
|
+
),
|
|
257
278
|
writeFile(serviceFile, serviceContent, {
|
|
258
279
|
overwriteExisting: force
|
|
259
280
|
})
|
|
@@ -296,9 +317,13 @@ async function handler(args) {
|
|
|
296
317
|
);
|
|
297
318
|
const serviceContent = ts ? exampleServiceTemplateContent : await transformTSToJS(serviceFile, exampleServiceTemplateContent);
|
|
298
319
|
return [
|
|
299
|
-
writeFile(
|
|
300
|
-
|
|
301
|
-
|
|
320
|
+
writeFile(
|
|
321
|
+
sdlFile,
|
|
322
|
+
withAuthDirective(sdlContent, { belongsToOrg: false }),
|
|
323
|
+
{
|
|
324
|
+
overwriteExisting: force
|
|
325
|
+
}
|
|
326
|
+
),
|
|
302
327
|
writeFile(serviceFile, serviceContent, {
|
|
303
328
|
overwriteExisting: force
|
|
304
329
|
})
|
|
@@ -18,9 +18,143 @@ function buildMembershipsSelectProperty() {
|
|
|
18
18
|
}
|
|
19
19
|
return property;
|
|
20
20
|
}
|
|
21
|
+
const TENANCY_AUTH_EXPORT = `export const { hasUserRole, hasOrgRole, requireUserAuth, requireOrgAuth } =
|
|
22
|
+
createTenancyAuth()
|
|
23
|
+
`;
|
|
24
|
+
const DEFAULT_REQUIRE_AUTH_STATEMENTS = [
|
|
25
|
+
/^if \(!isAuthenticated\(\)\) \{ throw new AuthenticationError\([^)]*\);? \}$/,
|
|
26
|
+
/^if \(roles && !hasRole\(roles\)\) \{ throw new ForbiddenError\([^)]*\);? \}$/,
|
|
27
|
+
/^return isAuthenticated\(\);?$/
|
|
28
|
+
];
|
|
29
|
+
const DEFAULT_HAS_ROLE_NAMES = /* @__PURE__ */ new Set([
|
|
30
|
+
"AllowedRoles",
|
|
31
|
+
"Array",
|
|
32
|
+
"allowedRole",
|
|
33
|
+
"allowedRoles",
|
|
34
|
+
"context",
|
|
35
|
+
"currentUser",
|
|
36
|
+
"currentUserRoles",
|
|
37
|
+
"hasRole",
|
|
38
|
+
"includes",
|
|
39
|
+
"isArray",
|
|
40
|
+
"isAuthenticated",
|
|
41
|
+
"role",
|
|
42
|
+
"roles",
|
|
43
|
+
"some",
|
|
44
|
+
"undefined"
|
|
45
|
+
]);
|
|
46
|
+
function exportedValue(declaration) {
|
|
47
|
+
const node = declaration.nodes()[0];
|
|
48
|
+
return j.VariableDeclaration.check(node?.declaration) ? node.declaration.declarations[0] : void 0;
|
|
49
|
+
}
|
|
50
|
+
function isDefaultHasRole(hasRole) {
|
|
51
|
+
return hasRole.find(j.Identifier).nodes().every((identifier) => DEFAULT_HAS_ROLE_NAMES.has(identifier.name));
|
|
52
|
+
}
|
|
53
|
+
function isDefaultRequireAuth(requireAuth) {
|
|
54
|
+
const declarator = exportedValue(requireAuth);
|
|
55
|
+
const fn = j.VariableDeclarator.check(declarator) ? declarator.init : null;
|
|
56
|
+
if (!j.ArrowFunctionExpression.check(fn) || !j.BlockStatement.check(fn.body)) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return fn.body.body.every((statement) => {
|
|
60
|
+
const source = j(statement).toSource().replace(/\/\/[^\n]*|\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").trim();
|
|
61
|
+
return DEFAULT_REQUIRE_AUTH_STATEMENTS.some(
|
|
62
|
+
(pattern) => pattern.test(source)
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function findExportedConst(root, name) {
|
|
67
|
+
return root.find(j.ExportNamedDeclaration, {
|
|
68
|
+
declaration: {
|
|
69
|
+
type: "VariableDeclaration",
|
|
70
|
+
declarations: [{ id: { type: "Identifier", name } }]
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const USER_LOOKUP = {
|
|
75
|
+
callee: {
|
|
76
|
+
type: "MemberExpression",
|
|
77
|
+
object: {
|
|
78
|
+
type: "MemberExpression",
|
|
79
|
+
object: { name: "db" },
|
|
80
|
+
property: { name: "user" }
|
|
81
|
+
},
|
|
82
|
+
property: { name: "findUnique" }
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
function addContextImport(root) {
|
|
86
|
+
const usesContext = root.find(j.Identifier, { name: "context" }).filter(
|
|
87
|
+
(path) => !(j.MemberExpression.check(path.parent.node) && path.parent.node.property === path.node && !path.parent.node.computed) && !(j.ObjectProperty.check(path.parent.node) && path.parent.node.key === path.node)
|
|
88
|
+
).length > 0;
|
|
89
|
+
const declaresContext = root.find(j.ImportDeclaration, {
|
|
90
|
+
source: { value: "@cedarjs/graphql-server" }
|
|
91
|
+
}).length > 0 || root.find(j.ImportSpecifier, { local: { name: "context" } }).length > 0 || root.find(j.VariableDeclarator, { id: { name: "context" } }).length > 0;
|
|
92
|
+
if (!usesContext || declaresContext) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
const contextImport = j.withParser("ts")(`import { context } from '@cedarjs/context'
|
|
96
|
+
`).find(j.ImportDeclaration).nodes()[0];
|
|
97
|
+
const cedarImports = root.find(j.ImportDeclaration).filter((path) => String(path.node.source.value).startsWith("@cedarjs/"));
|
|
98
|
+
const before = cedarImports.filter(
|
|
99
|
+
(path) => String(path.node.source.value) > "@cedarjs/context"
|
|
100
|
+
);
|
|
101
|
+
if (before.length > 0) {
|
|
102
|
+
before.at(0).insertBefore(contextImport);
|
|
103
|
+
} else if (cedarImports.length > 0) {
|
|
104
|
+
cedarImports.at(cedarImports.length - 1).insertAfter(contextImport);
|
|
105
|
+
} else {
|
|
106
|
+
root.find(j.Program).forEach((path) => {
|
|
107
|
+
path.node.body.unshift(contextImport);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
function addWithPermissions(root, lookups) {
|
|
113
|
+
const isWithPermissionsCall = (node) => j.CallExpression.check(node) && j.Identifier.check(node.callee) && node.callee.name === "withPermissions";
|
|
114
|
+
let wrapped = false;
|
|
115
|
+
root.find(j.CallExpression, USER_LOOKUP).forEach((path) => {
|
|
116
|
+
if (!lookups.has(path.node)) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const awaited = j.AwaitExpression.check(path.parent.node) ? path.parent : null;
|
|
120
|
+
const thenCall = path.parent.parent?.node;
|
|
121
|
+
const isThenWithPermissions = j.MemberExpression.check(path.parent.node) && j.Identifier.check(path.parent.node.property) && path.parent.node.property.name === "then" && j.CallExpression.check(thenCall) && j.Identifier.check(thenCall.arguments[0]) && thenCall.arguments[0].name === "withPermissions";
|
|
122
|
+
if (isWithPermissionsCall((awaited ?? path).parent.node) || isThenWithPermissions) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
wrapped = true;
|
|
126
|
+
if (awaited) {
|
|
127
|
+
awaited.replace(
|
|
128
|
+
j.callExpression(j.identifier("withPermissions"), [awaited.node])
|
|
129
|
+
);
|
|
130
|
+
} else {
|
|
131
|
+
path.replace(
|
|
132
|
+
j.callExpression(j.memberExpression(path.node, j.identifier("then")), [
|
|
133
|
+
j.identifier("withPermissions")
|
|
134
|
+
])
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
return wrapped;
|
|
139
|
+
}
|
|
140
|
+
function addPermissionsImport(source) {
|
|
141
|
+
if (/import \{[^}]*\bwithPermissions\b[^}]*\} from/.test(source)) {
|
|
142
|
+
return source;
|
|
143
|
+
}
|
|
144
|
+
const eol = source.includes("\r\n") ? "\r\n" : "\n";
|
|
145
|
+
const dbImport = /^import \{ db \} from (['"])(.*?)db(\.js)?\1;?\r?\n/m;
|
|
146
|
+
if (dbImport.test(source)) {
|
|
147
|
+
return source.replace(
|
|
148
|
+
dbImport,
|
|
149
|
+
(line, quote, dir, ext = "") => `${line}import { withPermissions } from ${quote}${dir}permissions${ext}${quote}${eol}`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
return `import { withPermissions } from 'src/lib/permissions'${eol}${source}`;
|
|
153
|
+
}
|
|
21
154
|
function transform(fileInfo) {
|
|
22
155
|
const root = j.withParser("tsx")(fileInfo.source);
|
|
23
156
|
let selectFound = false;
|
|
157
|
+
const membershipLookups = /* @__PURE__ */ new Set();
|
|
24
158
|
let changed = false;
|
|
25
159
|
root.find(j.CallExpression, {
|
|
26
160
|
callee: {
|
|
@@ -51,33 +185,64 @@ function transform(fileInfo) {
|
|
|
51
185
|
changed = true;
|
|
52
186
|
}
|
|
53
187
|
selectFound = true;
|
|
188
|
+
membershipLookups.add(path.node);
|
|
54
189
|
});
|
|
55
190
|
if (!selectFound) {
|
|
56
191
|
throw new Error("CEDAR_CODEMOD_ERR_AUTH_SHAPE_NOT_FOUND");
|
|
57
192
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
193
|
+
if (addWithPermissions(root, membershipLookups)) {
|
|
194
|
+
changed = true;
|
|
195
|
+
}
|
|
196
|
+
const alreadyWired = root.find(j.ImportSpecifier, { imported: { name: "createTenancyAuth" } }).length > 0;
|
|
197
|
+
if (alreadyWired) {
|
|
198
|
+
if (addContextImport(root)) {
|
|
199
|
+
changed = true;
|
|
64
200
|
}
|
|
201
|
+
return addPermissionsImport(changed ? root.toSource() : fileInfo.source);
|
|
202
|
+
}
|
|
203
|
+
const hasRole = findExportedConst(root, "hasRole");
|
|
204
|
+
const requireAuth = findExportedConst(root, "requireAuth");
|
|
205
|
+
if (hasRole.length !== 1 || requireAuth.length !== 1) {
|
|
206
|
+
throw new Error("CEDAR_CODEMOD_ERR_AUTH_CHECKS_NOT_FOUND");
|
|
207
|
+
}
|
|
208
|
+
if (!isDefaultRequireAuth(requireAuth) || !isDefaultHasRole(hasRole)) {
|
|
209
|
+
throw new Error("CEDAR_CODEMOD_ERR_AUTH_CHECKS_CHANGED");
|
|
210
|
+
}
|
|
211
|
+
const tenancyAuth = j.withParser("ts")(TENANCY_AUTH_EXPORT).find(j.ExportNamedDeclaration).nodes()[0];
|
|
212
|
+
requireAuth.replaceWith(tenancyAuth);
|
|
213
|
+
hasRole.remove();
|
|
214
|
+
root.find(j.Identifier, { name: "hasRole" }).filter(
|
|
215
|
+
(path) => !(j.MemberExpression.check(path.parent.node) && path.parent.node.property === path.node)
|
|
216
|
+
).forEach((path) => {
|
|
217
|
+
path.node.name = "hasUserRole";
|
|
65
218
|
});
|
|
66
|
-
const
|
|
67
|
-
(
|
|
219
|
+
const isUnused = (name) => root.find(j.Identifier, { name }).filter(
|
|
220
|
+
(path) => !j.ImportSpecifier.check(path.parent.node) && !j.TSTypeAliasDeclaration.check(path.parent.node)
|
|
221
|
+
).length === 0;
|
|
222
|
+
root.find(j.TSTypeAliasDeclaration, { id: { name: "AllowedRoles" } }).filter(() => isUnused("AllowedRoles")).remove();
|
|
223
|
+
root.find(j.ImportDeclaration, { source: { value: "@cedarjs/graphql-server" } }).forEach((path) => {
|
|
224
|
+
path.node.specifiers = (path.node.specifiers ?? []).filter(
|
|
225
|
+
(specifier) => !j.ImportSpecifier.check(specifier) || !j.Identifier.check(specifier.local) || !isUnused(specifier.local.name)
|
|
226
|
+
);
|
|
227
|
+
}).filter((path) => (path.node.specifiers ?? []).length === 0).remove();
|
|
228
|
+
const tenancyImport = j.withParser("ts")(`import { createTenancyAuth } from '@cedarjs/tenancy'
|
|
229
|
+
`).find(j.ImportDeclaration).nodes()[0];
|
|
230
|
+
const imports = root.find(j.ImportDeclaration);
|
|
231
|
+
const cedarImports = imports.filter(
|
|
232
|
+
(path) => String(path.node.source.value).startsWith("@cedarjs/")
|
|
68
233
|
);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
).find(j.ExportNamedDeclaration).nodes()[0];
|
|
234
|
+
const anchor = cedarImports.length > 0 ? cedarImports : imports;
|
|
235
|
+
if (anchor.length > 0) {
|
|
236
|
+
anchor.at(anchor.length - 1).insertAfter(tenancyImport);
|
|
237
|
+
} else {
|
|
74
238
|
root.find(j.Program).forEach((path) => {
|
|
75
|
-
path.node.body.
|
|
239
|
+
path.node.body.unshift(tenancyImport);
|
|
76
240
|
});
|
|
77
|
-
changed = true;
|
|
78
241
|
}
|
|
79
|
-
|
|
242
|
+
addContextImport(root);
|
|
243
|
+
return addPermissionsImport(root.toSource());
|
|
80
244
|
}
|
|
81
245
|
export {
|
|
246
|
+
TENANCY_AUTH_EXPORT,
|
|
82
247
|
transform as default
|
|
83
248
|
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
function renameRequireAuthDirective(source) {
|
|
2
|
+
return source.replace(/@requireAuth(?![\w$])/g, "@requireUserAuth");
|
|
3
|
+
}
|
|
4
|
+
const LIB_AUTH_IMPORT = /import\s*\{([^}]*)\}\s*from\s*(['"])((?:src|\.{1,2})(?:\/[^'"]*)?\/lib\/auth(?:\.[jt]s)?)\2/g;
|
|
5
|
+
const LIB_AUTH_RENAMES = {
|
|
6
|
+
requireAuth: "requireUserAuth",
|
|
7
|
+
hasRole: "hasUserRole"
|
|
8
|
+
};
|
|
9
|
+
function renameLibAuthImports(source) {
|
|
10
|
+
let result = source;
|
|
11
|
+
for (const [from, to] of Object.entries(LIB_AUTH_RENAMES)) {
|
|
12
|
+
let renameUses = false;
|
|
13
|
+
result = result.replace(
|
|
14
|
+
LIB_AUTH_IMPORT,
|
|
15
|
+
(statement, specifiers) => {
|
|
16
|
+
const renamed = specifiers.replace(
|
|
17
|
+
new RegExp(`(?<![\\w$])${from}(?![\\w$])(\\s+as\\s+[\\w$]+)?`, "g"),
|
|
18
|
+
(_specifier, alias) => {
|
|
19
|
+
if (!alias) {
|
|
20
|
+
renameUses = true;
|
|
21
|
+
}
|
|
22
|
+
return `${to}${alias ?? ""}`;
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
return statement.replace(specifiers, renamed);
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
if (renameUses) {
|
|
29
|
+
result = result.replace(
|
|
30
|
+
new RegExp(`(?<![\\w$@.])${from}(?![\\w$])`, "g"),
|
|
31
|
+
to
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
const DEFAULT_REQUIRE_AUTH_DIRECTIVES = [
|
|
38
|
+
`import { gql } from 'graphql-tag'
|
|
39
|
+
|
|
40
|
+
import type { ValidatorDirectiveFunc } from '@cedarjs/graphql-server'
|
|
41
|
+
import { createValidatorDirective } from '@cedarjs/graphql-server'
|
|
42
|
+
|
|
43
|
+
import { requireAuth as applicationRequireAuth } from 'src/lib/auth'
|
|
44
|
+
|
|
45
|
+
export const schema = gql\`
|
|
46
|
+
"""
|
|
47
|
+
Use to check whether or not a user is authenticated and is associated
|
|
48
|
+
with an optional set of roles.
|
|
49
|
+
"""
|
|
50
|
+
directive @requireAuth(roles: [String]) on FIELD_DEFINITION
|
|
51
|
+
\`
|
|
52
|
+
|
|
53
|
+
type RequireAuthValidate = ValidatorDirectiveFunc<{ roles?: string[] }>
|
|
54
|
+
|
|
55
|
+
const validate: RequireAuthValidate = ({ directiveArgs }) => {
|
|
56
|
+
const { roles } = directiveArgs
|
|
57
|
+
applicationRequireAuth({ roles })
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const requireAuth = createValidatorDirective(schema, validate)
|
|
61
|
+
|
|
62
|
+
export default requireAuth
|
|
63
|
+
`,
|
|
64
|
+
`import { gql } from 'graphql-tag'
|
|
65
|
+
|
|
66
|
+
import { createValidatorDirective } from '@cedarjs/graphql-server'
|
|
67
|
+
|
|
68
|
+
import { requireAuth as applicationRequireAuth } from 'src/lib/auth'
|
|
69
|
+
|
|
70
|
+
export const schema = gql\`
|
|
71
|
+
"""
|
|
72
|
+
Use to check whether or not a user is authenticated and is associated
|
|
73
|
+
with an optional set of roles.
|
|
74
|
+
"""
|
|
75
|
+
directive @requireAuth(roles: [String]) on FIELD_DEFINITION
|
|
76
|
+
\`
|
|
77
|
+
|
|
78
|
+
const validate = ({ directiveArgs }) => {
|
|
79
|
+
const { roles } = directiveArgs
|
|
80
|
+
applicationRequireAuth({ roles })
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const requireAuth = createValidatorDirective(schema, validate)
|
|
84
|
+
|
|
85
|
+
export default requireAuth
|
|
86
|
+
`
|
|
87
|
+
];
|
|
88
|
+
function withoutFormatting(source) {
|
|
89
|
+
return source.replace(/\/\*[\s\S]*?\*\/|\/\/[^\n]*/g, "").replace(/["']/g, "'").replace(/[;\s]/g, "").replace(/,([)\]}>])/g, "$1");
|
|
90
|
+
}
|
|
91
|
+
function isDefaultRequireAuthDirective(source) {
|
|
92
|
+
return DEFAULT_REQUIRE_AUTH_DIRECTIVES.some(
|
|
93
|
+
(directive) => withoutFormatting(directive) === withoutFormatting(source)
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
export {
|
|
97
|
+
DEFAULT_REQUIRE_AUTH_DIRECTIVES,
|
|
98
|
+
isDefaultRequireAuthDirective,
|
|
99
|
+
renameLibAuthImports,
|
|
100
|
+
renameRequireAuthDirective
|
|
101
|
+
};
|