@canmingir/link-express 1.6.1 → 1.6.3
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/package.json +1 -1
- package/src/lib/test.js +15 -4
- package/src/routes/oauth.js +51 -48
- package/src/routes/test/oauth.spec.js +47 -21
- package/src/seeds/Permission.json +164 -164
package/package.json
CHANGED
package/src/lib/test.js
CHANGED
|
@@ -7,10 +7,21 @@ init({
|
|
|
7
7
|
jwt: {
|
|
8
8
|
identifier: "email",
|
|
9
9
|
},
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
providers: {
|
|
11
|
+
github: {
|
|
12
|
+
tokenUrl: "https://github.com/login/oauth/access_token",
|
|
13
|
+
userUrl: "https://api.github.com/user",
|
|
14
|
+
clientId: "0c2844d3d19dc9293fc5",
|
|
15
|
+
redirectUri: "http://localhost:5173/callback",
|
|
16
|
+
userIdentifier: "id",
|
|
17
|
+
userFields: {
|
|
18
|
+
name: "name",
|
|
19
|
+
displayName: "login",
|
|
20
|
+
avatarUrl: "avatar_url",
|
|
21
|
+
email: "email",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
14
25
|
},
|
|
15
26
|
},
|
|
16
27
|
postgres: {
|
package/src/routes/oauth.js
CHANGED
|
@@ -3,24 +3,25 @@ const router = require("express").Router();
|
|
|
3
3
|
const jwt = require("jsonwebtoken");
|
|
4
4
|
const axios = require("axios");
|
|
5
5
|
const config = require("../config");
|
|
6
|
-
const { AuthenticationError } = require("../error");
|
|
6
|
+
const { AuthenticationError, AuthorizationError } = require("../error");
|
|
7
7
|
const Permission = require("../models/Permission");
|
|
8
8
|
const { project } = config();
|
|
9
9
|
|
|
10
10
|
router.post("/", async (req, res) => {
|
|
11
|
-
let { appId, projectId, code, refreshToken, redirectUri, provider } =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
let { appId, projectId, code, refreshToken, redirectUri, provider } =
|
|
12
|
+
Joi.attempt(
|
|
13
|
+
req.body,
|
|
14
|
+
Joi.object({
|
|
15
|
+
appId: Joi.string().required(),
|
|
16
|
+
projectId: Joi.string().optional(),
|
|
17
|
+
code: Joi.string().optional(),
|
|
18
|
+
refreshToken: Joi.string().optional(),
|
|
19
|
+
redirectUri: Joi.string().optional(),
|
|
20
|
+
provider: Joi.string().required(),
|
|
21
|
+
})
|
|
22
|
+
.required()
|
|
23
|
+
.options({ stripUnknown: true })
|
|
24
|
+
);
|
|
24
25
|
|
|
25
26
|
if (!code && !refreshToken) {
|
|
26
27
|
return res.status(400).send("Missing OAuth Code and Refresh Token");
|
|
@@ -38,7 +39,10 @@ router.post("/", async (req, res) => {
|
|
|
38
39
|
const params = new URLSearchParams();
|
|
39
40
|
params.append("grant_type", "authorization_code");
|
|
40
41
|
params.append("client_id", providerConfig.clientId);
|
|
41
|
-
params.append(
|
|
42
|
+
params.append(
|
|
43
|
+
"client_secret",
|
|
44
|
+
process.env[`${provider.toUpperCase()}_CLIENT_SECRET`]
|
|
45
|
+
);
|
|
42
46
|
params.append("code", code);
|
|
43
47
|
params.append("redirect_uri", redirectUri);
|
|
44
48
|
|
|
@@ -48,35 +52,37 @@ router.post("/", async (req, res) => {
|
|
|
48
52
|
{
|
|
49
53
|
headers: {
|
|
50
54
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
51
|
-
|
|
55
|
+
Accept: "application/json",
|
|
52
56
|
},
|
|
53
|
-
timeout: 10000
|
|
57
|
+
timeout: 10000,
|
|
54
58
|
}
|
|
55
59
|
);
|
|
56
60
|
|
|
57
61
|
if (tokenResponse.data.error) {
|
|
58
|
-
throw new
|
|
62
|
+
throw new AuthorizationError(
|
|
59
63
|
tokenResponse.data.error_description || tokenResponse.data.error
|
|
60
64
|
);
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
if (!tokenResponse.data.access_token) {
|
|
64
|
-
throw new AuthenticationError(
|
|
68
|
+
throw new AuthenticationError(
|
|
69
|
+
"No access token received from OAuth provider"
|
|
70
|
+
);
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
accessTokenForAPI = tokenResponse.data.access_token;
|
|
68
|
-
newRefreshToken =
|
|
74
|
+
newRefreshToken =
|
|
75
|
+
tokenResponse.data.refresh_token || tokenResponse.data.access_token;
|
|
69
76
|
} else {
|
|
70
77
|
accessTokenForAPI = refreshToken;
|
|
71
78
|
}
|
|
72
79
|
|
|
73
|
-
|
|
74
80
|
let userResponse = await axios.get(providerConfig.userUrl, {
|
|
75
81
|
headers: {
|
|
76
82
|
Authorization: `Bearer ${accessTokenForAPI}`,
|
|
77
|
-
|
|
83
|
+
Accept: "application/json",
|
|
78
84
|
},
|
|
79
|
-
timeout: 10000
|
|
85
|
+
timeout: 10000,
|
|
80
86
|
});
|
|
81
87
|
|
|
82
88
|
console.log("User info response:", userResponse.data);
|
|
@@ -92,28 +98,28 @@ router.post("/", async (req, res) => {
|
|
|
92
98
|
console.error("User identifier extraction failed:", {
|
|
93
99
|
availableFields: Object.keys(userResponse.data),
|
|
94
100
|
expectedField: identifierField,
|
|
95
|
-
fallbackField: project.oauth.jwt.identifier
|
|
101
|
+
fallbackField: project.oauth.jwt.identifier,
|
|
96
102
|
});
|
|
97
|
-
throw new Error(
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Cannot find user identifier in ${provider} OAuth response`
|
|
105
|
+
);
|
|
98
106
|
}
|
|
99
107
|
|
|
100
|
-
const prefixedUserId = `${provider}_${userId}`;
|
|
101
|
-
|
|
102
108
|
let accessToken;
|
|
103
109
|
|
|
104
110
|
if (projectId) {
|
|
105
111
|
const permissions = await Permission.findAll({
|
|
106
|
-
where: { userId
|
|
112
|
+
where: { userId, projectId, appId },
|
|
107
113
|
});
|
|
108
114
|
|
|
109
115
|
if (!permissions.length) {
|
|
110
116
|
accessToken = jwt.sign(
|
|
111
117
|
{
|
|
112
|
-
sub:
|
|
118
|
+
sub: userId,
|
|
113
119
|
iss: "nuc",
|
|
114
120
|
aid: appId,
|
|
115
121
|
provider: provider,
|
|
116
|
-
iat: Math.floor(Date.now() / 1000)
|
|
122
|
+
iat: Math.floor(Date.now() / 1000),
|
|
117
123
|
},
|
|
118
124
|
process.env.JWT_SECRET,
|
|
119
125
|
{ expiresIn: "12h" }
|
|
@@ -121,14 +127,14 @@ router.post("/", async (req, res) => {
|
|
|
121
127
|
} else {
|
|
122
128
|
accessToken = jwt.sign(
|
|
123
129
|
{
|
|
124
|
-
sub:
|
|
130
|
+
sub: userId,
|
|
125
131
|
iss: "nuc",
|
|
126
132
|
aud: projectId,
|
|
127
133
|
oid: permissions[0].organizationId,
|
|
128
134
|
aid: appId,
|
|
129
135
|
rls: permissions.map((permission) => permission.role),
|
|
130
136
|
provider: provider,
|
|
131
|
-
iat: Math.floor(Date.now() / 1000)
|
|
137
|
+
iat: Math.floor(Date.now() / 1000),
|
|
132
138
|
},
|
|
133
139
|
process.env.JWT_SECRET,
|
|
134
140
|
{ expiresIn: "12h" }
|
|
@@ -137,11 +143,11 @@ router.post("/", async (req, res) => {
|
|
|
137
143
|
} else {
|
|
138
144
|
accessToken = jwt.sign(
|
|
139
145
|
{
|
|
140
|
-
sub:
|
|
146
|
+
sub: userId,
|
|
141
147
|
iss: "nuc",
|
|
142
148
|
aid: appId,
|
|
143
149
|
provider: provider,
|
|
144
|
-
iat: Math.floor(Date.now() / 1000)
|
|
150
|
+
iat: Math.floor(Date.now() / 1000),
|
|
145
151
|
},
|
|
146
152
|
process.env.JWT_SECRET,
|
|
147
153
|
{ expiresIn: "12h" }
|
|
@@ -150,16 +156,15 @@ router.post("/", async (req, res) => {
|
|
|
150
156
|
|
|
151
157
|
res.status(200).json({
|
|
152
158
|
accessToken,
|
|
153
|
-
refreshToken: newRefreshToken
|
|
159
|
+
refreshToken: newRefreshToken,
|
|
154
160
|
});
|
|
155
161
|
});
|
|
156
162
|
|
|
157
163
|
router.get("/user", async (req, res) => {
|
|
158
164
|
const authHeader = req.headers.authorization;
|
|
159
|
-
const refreshTokenHeader = req.headers[
|
|
160
|
-
|
|
165
|
+
const refreshTokenHeader = req.headers["x-refresh-token"];
|
|
161
166
|
|
|
162
|
-
if (!authHeader || !authHeader.startsWith(
|
|
167
|
+
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
163
168
|
return res.status(401).end();
|
|
164
169
|
}
|
|
165
170
|
|
|
@@ -167,12 +172,12 @@ router.get("/user", async (req, res) => {
|
|
|
167
172
|
return res.status(400).send("Missing refresh token");
|
|
168
173
|
}
|
|
169
174
|
|
|
170
|
-
const token = authHeader.split(
|
|
171
|
-
|
|
175
|
+
const token = authHeader.split(" ")[1];
|
|
176
|
+
|
|
172
177
|
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
|
173
178
|
const userId = decoded.sub;
|
|
174
179
|
const provider = decoded.provider;
|
|
175
|
-
|
|
180
|
+
|
|
176
181
|
if (!userId || !provider) {
|
|
177
182
|
return res.status(401).end();
|
|
178
183
|
}
|
|
@@ -182,16 +187,14 @@ router.get("/user", async (req, res) => {
|
|
|
182
187
|
return res.status(400).send("Unsupported OAuth provider");
|
|
183
188
|
}
|
|
184
189
|
|
|
185
|
-
|
|
186
190
|
const userResponse = await axios.get(providerConfig.userUrl, {
|
|
187
191
|
headers: {
|
|
188
192
|
Authorization: `Bearer ${refreshTokenHeader}`,
|
|
189
|
-
|
|
193
|
+
Accept: "application/json",
|
|
190
194
|
},
|
|
191
|
-
timeout: 10000
|
|
195
|
+
timeout: 10000,
|
|
192
196
|
});
|
|
193
197
|
|
|
194
|
-
|
|
195
198
|
const userFieldMapping = providerConfig.userFields;
|
|
196
199
|
const userDetails = {
|
|
197
200
|
id: userId,
|
|
@@ -199,12 +202,12 @@ router.get("/user", async (req, res) => {
|
|
|
199
202
|
name: userResponse.data[userFieldMapping.name] || null,
|
|
200
203
|
displayName: userResponse.data[userFieldMapping.displayName] || null,
|
|
201
204
|
avatarUrl: userResponse.data[userFieldMapping.avatarUrl] || null,
|
|
202
|
-
email: userResponse.data[userFieldMapping.email] || null
|
|
205
|
+
email: userResponse.data[userFieldMapping.email] || null,
|
|
203
206
|
};
|
|
204
207
|
|
|
205
208
|
res.status(200).json({
|
|
206
|
-
user: userDetails
|
|
209
|
+
user: userDetails,
|
|
207
210
|
});
|
|
208
211
|
});
|
|
209
212
|
|
|
210
|
-
module.exports = router;
|
|
213
|
+
module.exports = router;
|
|
@@ -5,7 +5,7 @@ const app = platform.express();
|
|
|
5
5
|
|
|
6
6
|
const request = require("supertest");
|
|
7
7
|
const jwt = require("jsonwebtoken");
|
|
8
|
-
const { equal } = require("assert");
|
|
8
|
+
const { equal, deepEqual } = require("assert");
|
|
9
9
|
const config = require("../../config");
|
|
10
10
|
const { project } = config();
|
|
11
11
|
|
|
@@ -19,14 +19,16 @@ describe("OAuth", () => {
|
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
it("returns accessToken and refreshToken with code", async () => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
const provider = "github";
|
|
23
|
+
const providerConfig = project.oauth.providers[provider];
|
|
24
|
+
|
|
25
|
+
mock.onPost(providerConfig.tokenUrl).reply(200, {
|
|
26
|
+
access_token: "c9Q2KuluvCGdM4YZiUnGWxImvuFnbv",
|
|
27
|
+
token_type: "bearer",
|
|
28
|
+
scope: "user",
|
|
29
|
+
});
|
|
28
30
|
|
|
29
|
-
mock.onGet(
|
|
31
|
+
mock.onGet(providerConfig.userUrl).reply(200, { id: "1001" });
|
|
30
32
|
|
|
31
33
|
const {
|
|
32
34
|
body: { accessToken, refreshToken },
|
|
@@ -35,8 +37,9 @@ describe("OAuth", () => {
|
|
|
35
37
|
.send({
|
|
36
38
|
appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
37
39
|
projectId: "cb16e069-6214-47f1-9922-1f7fe7629525",
|
|
38
|
-
redirectUri:
|
|
40
|
+
redirectUri: providerConfig.redirectUri,
|
|
39
41
|
code: "vImIDQtMVcYnUCI3Brp6",
|
|
42
|
+
provider: provider,
|
|
40
43
|
})
|
|
41
44
|
.expect(200);
|
|
42
45
|
|
|
@@ -44,17 +47,21 @@ describe("OAuth", () => {
|
|
|
44
47
|
|
|
45
48
|
equal(payload.iss, "nuc");
|
|
46
49
|
equal(payload.aud, "cb16e069-6214-47f1-9922-1f7fe7629525");
|
|
47
|
-
equal(payload.sub,
|
|
48
|
-
|
|
50
|
+
equal(payload.sub, `1001`);
|
|
51
|
+
deepEqual(payload.rls, ["OWNER"]);
|
|
49
52
|
equal(payload.aid, "977f5f57-8936-4388-8eb0-00a512cf01cc");
|
|
50
53
|
equal(payload.oid, "dfb990bb-81dd-4584-82ce-050eb8f6a12f");
|
|
54
|
+
equal(payload.provider, provider);
|
|
51
55
|
equal(refreshToken, "c9Q2KuluvCGdM4YZiUnGWxImvuFnbv");
|
|
52
56
|
});
|
|
53
57
|
|
|
54
58
|
it("returns accessToken and refreshToken with refresh token", async () => {
|
|
59
|
+
const provider = "github";
|
|
60
|
+
const providerConfig = project.oauth.providers[provider];
|
|
61
|
+
|
|
55
62
|
mock
|
|
56
|
-
.onGet(
|
|
57
|
-
.reply(200, {
|
|
63
|
+
.onGet(providerConfig.userUrl)
|
|
64
|
+
.reply(200, { id: "liam@rebellioncoffee.shop" });
|
|
58
65
|
|
|
59
66
|
const {
|
|
60
67
|
body: { accessToken, refreshToken },
|
|
@@ -63,42 +70,59 @@ describe("OAuth", () => {
|
|
|
63
70
|
.send({
|
|
64
71
|
appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
65
72
|
refreshToken: "lzk7FZGga5hHrfiAePtswijiJHIOev",
|
|
73
|
+
provider: provider,
|
|
66
74
|
})
|
|
67
75
|
.expect(200);
|
|
68
76
|
|
|
69
77
|
const payload = jwt.decode(accessToken);
|
|
70
78
|
|
|
71
|
-
equal(payload.sub,
|
|
79
|
+
equal(payload.sub, `liam@rebellioncoffee.shop`);
|
|
72
80
|
equal(payload.iss, "nuc");
|
|
81
|
+
equal(payload.provider, provider);
|
|
73
82
|
equal(refreshToken, "lzk7FZGga5hHrfiAePtswijiJHIOev");
|
|
74
83
|
});
|
|
75
84
|
|
|
76
85
|
it("returns 400 if code and refreshToken are missing", async () => {
|
|
77
|
-
await request(app)
|
|
86
|
+
await request(app)
|
|
87
|
+
.post("/oauth")
|
|
88
|
+
.send({
|
|
89
|
+
appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
90
|
+
provider: "github",
|
|
91
|
+
})
|
|
92
|
+
.expect(400);
|
|
78
93
|
});
|
|
79
94
|
|
|
80
95
|
it("returns 401 if code is invalid", async () => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
mock.
|
|
96
|
+
const provider = "github";
|
|
97
|
+
const providerConfig = project.oauth.providers[provider];
|
|
98
|
+
|
|
99
|
+
mock.onPost(providerConfig.tokenUrl).reply(200, {
|
|
100
|
+
error: "bad_verification_code",
|
|
101
|
+
});
|
|
102
|
+
mock.onGet(providerConfig.userUrl).reply(401);
|
|
85
103
|
|
|
86
104
|
const res = await request(app).post("/oauth").send({
|
|
87
105
|
appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
88
106
|
code: "ZpodRqsLu2EJxbVrcqnV",
|
|
107
|
+
redirectUri: providerConfig.redirectUri,
|
|
108
|
+
provider: provider,
|
|
89
109
|
});
|
|
90
110
|
equal(res.status, 401);
|
|
91
111
|
});
|
|
92
112
|
|
|
93
113
|
it("returns 503 if OAuth Provider is not accessible", async () => {
|
|
94
|
-
|
|
95
|
-
|
|
114
|
+
const provider = "github";
|
|
115
|
+
const providerConfig = project.oauth.providers[provider];
|
|
116
|
+
|
|
117
|
+
mock.onPost(providerConfig.tokenUrl).networkError();
|
|
118
|
+
mock.onGet(providerConfig.userUrl).networkError();
|
|
96
119
|
|
|
97
120
|
await request(app)
|
|
98
121
|
.post("/oauth")
|
|
99
122
|
.send({
|
|
100
123
|
appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
101
124
|
refreshToken: "WnhGHF55s6HFRgpRL9AcV2N2VcYemj",
|
|
125
|
+
provider: provider,
|
|
102
126
|
})
|
|
103
127
|
.expect(503);
|
|
104
128
|
|
|
@@ -107,6 +131,8 @@ describe("OAuth", () => {
|
|
|
107
131
|
.send({
|
|
108
132
|
appId: "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
109
133
|
code: "RwlaK2waOdbAa4tt19RF",
|
|
134
|
+
redirectUri: providerConfig.redirectUri,
|
|
135
|
+
provider: provider,
|
|
110
136
|
})
|
|
111
137
|
.expect(503);
|
|
112
138
|
});
|
|
@@ -1,165 +1,165 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
2
|
+
"sequence": 9007199254740991,
|
|
3
|
+
"seed": [
|
|
4
|
+
{
|
|
5
|
+
"id": "e81887da-d05f-4959-9def-6cd137857088",
|
|
6
|
+
"appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
7
|
+
"organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
|
|
8
|
+
"projectId": "cb16e069-6214-47f1-9922-1f7fe7629525",
|
|
9
|
+
"userId": "1001",
|
|
10
|
+
"role": "OWNER"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": "b8e498d4-2d79-4e6e-b098-6a97e1d89a94",
|
|
14
|
+
"appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
|
|
15
|
+
"organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
|
|
16
|
+
"projectId": "add6dfa4-45ba-4da2-bc5c-5a529610b52f",
|
|
17
|
+
"userId": "1001",
|
|
18
|
+
"role": "OWNER"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "30044ea7-aa19-4696-876b-26fa76bb91f3",
|
|
22
|
+
"appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
23
|
+
"organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
|
|
24
|
+
"projectId": "0c756054-2d28-4f87-9b12-8023a79136a5",
|
|
25
|
+
"userId": "1001",
|
|
26
|
+
"role": "OWNER"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "973dfaff-0718-4d2d-a714-587cf7a44b98",
|
|
30
|
+
"appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
|
|
31
|
+
"organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
|
|
32
|
+
"projectId": "e6d4744d-a11b-4c75-acad-e24a02903729",
|
|
33
|
+
"userId": "1001",
|
|
34
|
+
"role": "OWNER"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": "4ecc380a-b480-4faa-ad47-878dd2ee4264",
|
|
38
|
+
"appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
39
|
+
"organizationId": "5459ab03-204a-4627-bdde-667b7802cb35",
|
|
40
|
+
"projectId": "21d2530b-4657-4ac0-b8cd-1a9f82786e32",
|
|
41
|
+
"userId": "1001",
|
|
42
|
+
"role": "OWNER"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"id": "a1b60c53-66e2-4034-8654-38b83577f279",
|
|
46
|
+
"appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
47
|
+
"organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
|
|
48
|
+
"projectId": "cb16e069-6214-47f1-9922-1f7fe7629525",
|
|
49
|
+
"userId": "49736917",
|
|
50
|
+
"role": "OWNER"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": "e2809e32-b025-4592-855f-dd2b8f49e1b2",
|
|
54
|
+
"appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
|
|
55
|
+
"organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
|
|
56
|
+
"projectId": "add6dfa4-45ba-4da2-bc5c-5a529610b52f",
|
|
57
|
+
"userId": "49736917",
|
|
58
|
+
"role": "OWNER"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": "9fc7dd4e-97ef-47a5-987c-99f8015fc736",
|
|
62
|
+
"appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
63
|
+
"organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
|
|
64
|
+
"projectId": "0c756054-2d28-4f87-9b12-8023a79136a5",
|
|
65
|
+
"userId": "49736917",
|
|
66
|
+
"role": "OWNER"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"id": "b8302e81-4a44-4358-978f-21e9219ead61",
|
|
70
|
+
"appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
|
|
71
|
+
"organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
|
|
72
|
+
"projectId": "e6d4744d-a11b-4c75-acad-e24a02903729",
|
|
73
|
+
"userId": "49736917",
|
|
74
|
+
"role": "OWNER"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "4758a390-4968-44bd-aafe-abdee8044a01",
|
|
78
|
+
"appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
79
|
+
"organizationId": "5459ab03-204a-4627-bdde-667b7802cb35",
|
|
80
|
+
"projectId": "21d2530b-4657-4ac0-b8cd-1a9f82786e32",
|
|
81
|
+
"userId": "49736917",
|
|
82
|
+
"role": "OWNER"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"id": "38b1cc0c-46d8-4f95-9be9-0df1a6c91d7b",
|
|
86
|
+
"appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
87
|
+
"organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
|
|
88
|
+
"projectId": "cb16e069-6214-47f1-9922-1f7fe7629525",
|
|
89
|
+
"userId": "54210920",
|
|
90
|
+
"role": "OWNER"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"id": "03a1eb7b-b25a-4b44-9484-f8b93d8a9e5b",
|
|
94
|
+
"appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
|
|
95
|
+
"organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
|
|
96
|
+
"projectId": "add6dfa4-45ba-4da2-bc5c-5a529610b52f",
|
|
97
|
+
"userId": "54210920",
|
|
98
|
+
"role": "OWNER"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"id": "e54b340d-e1d7-452d-8422-13cae24b0a9f",
|
|
102
|
+
"appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
103
|
+
"organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
|
|
104
|
+
"projectId": "0c756054-2d28-4f87-9b12-8023a79136a5",
|
|
105
|
+
"userId": "54210920",
|
|
106
|
+
"role": "OWNER"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"id": "fce2b3bb-2776-43d8-bb35-14633882b899",
|
|
110
|
+
"appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
|
|
111
|
+
"organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
|
|
112
|
+
"projectId": "e6d4744d-a11b-4c75-acad-e24a02903729",
|
|
113
|
+
"userId": "54210920",
|
|
114
|
+
"role": "OWNER"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"id": "9067f420-9c22-4578-81b6-aa0d88213f24",
|
|
118
|
+
"appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
119
|
+
"organizationId": "5459ab03-204a-4627-bdde-667b7802cb35",
|
|
120
|
+
"projectId": "21d2530b-4657-4ac0-b8cd-1a9f82786e32",
|
|
121
|
+
"userId": "54210920",
|
|
122
|
+
"role": "OWNER"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"id": "7f7bd2c8-3c27-455c-814e-1874e96246ed",
|
|
126
|
+
"appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
127
|
+
"organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
|
|
128
|
+
"projectId": "cb16e069-6214-47f1-9922-1f7fe7629525",
|
|
129
|
+
"userId": "90180086",
|
|
130
|
+
"role": "OWNER"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"id": "f09e5539-a983-424c-943f-f9c0e5cffa4e",
|
|
134
|
+
"appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
|
|
135
|
+
"organizationId": "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
|
|
136
|
+
"projectId": "add6dfa4-45ba-4da2-bc5c-5a529610b52f",
|
|
137
|
+
"userId": "90180086",
|
|
138
|
+
"role": "OWNER"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"id": "bd4d6afe-4592-4739-84af-011760879b3d",
|
|
142
|
+
"appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
143
|
+
"organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
|
|
144
|
+
"projectId": "0c756054-2d28-4f87-9b12-8023a79136a5",
|
|
145
|
+
"userId": "90180086",
|
|
146
|
+
"role": "OWNER"
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"id": "5c76772d-40af-464d-ae35-4415bbddc3cf",
|
|
150
|
+
"appId": "10b7bc8c-a49c-4002-b0ec-63599e4b5210",
|
|
151
|
+
"organizationId": "1c063446-7e78-432a-a273-34f481d0f0c3",
|
|
152
|
+
"projectId": "e6d4744d-a11b-4c75-acad-e24a02903729",
|
|
153
|
+
"userId": "90180086",
|
|
154
|
+
"role": "OWNER"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"id": "20d0920f-00bb-404f-a01e-1ab40eaa8583",
|
|
158
|
+
"appId": "977f5f57-8936-4388-8eb0-00a512cf01cc",
|
|
159
|
+
"organizationId": "5459ab03-204a-4627-bdde-667b7802cb35",
|
|
160
|
+
"projectId": "21d2530b-4657-4ac0-b8cd-1a9f82786e32",
|
|
161
|
+
"userId": "90180086",
|
|
162
|
+
"role": "OWNER"
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
}
|