@arcote.tech/arc-host 0.1.4 → 0.1.5
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/host.d.ts +4 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/index.js +35 -10
- package/host.ts +56 -9
- package/package.json +1 -1
package/dist/host.d.ts
CHANGED
|
@@ -15,6 +15,10 @@ declare class RTCHost implements RealTimeCommunicationAdapter {
|
|
|
15
15
|
* Convert JWT payload to AuthContext
|
|
16
16
|
*/
|
|
17
17
|
private tokenToAuthContext;
|
|
18
|
+
/**
|
|
19
|
+
* Extract client IP address from request headers
|
|
20
|
+
*/
|
|
21
|
+
private getClientIpAddress;
|
|
18
22
|
/**
|
|
19
23
|
* Get default auth context for anonymous users
|
|
20
24
|
*/
|
package/dist/host.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../host.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,aAAa,EAElB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EAGvB,KAAK,4BAA4B,EAClC,MAAM,kBAAkB,CAAC;AAI1B,cAAM,OAAQ,YAAW,4BAA4B;IAMjD,OAAO,CAAC,OAAO;IALjB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,KAAK,CAAuB;gBAG1B,OAAO,EAAE,aAAa,EAC9B,SAAS,EAAE,OAAO,CAAC,eAAe,CAAC;IASrC,aAAa,CAAC,OAAO,EAAE,kBAAkB,EAAE,GAAG,IAAI;IAI5C,IAAI,CACR,gBAAgB,EAAE,CAAC,EACjB,KAAK,EACL,IAAI,GACL,EAAE;QACD,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,KAAK,IAAI,GACT,OAAO,CAAC,IAAI,CAAC;YAIF,eAAe;
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../host.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,aAAa,EAElB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EAGvB,KAAK,4BAA4B,EAClC,MAAM,kBAAkB,CAAC;AAI1B,cAAM,OAAQ,YAAW,4BAA4B;IAMjD,OAAO,CAAC,OAAO;IALjB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,KAAK,CAAuB;gBAG1B,OAAO,EAAE,aAAa,EAC9B,SAAS,EAAE,OAAO,CAAC,eAAe,CAAC;IASrC,aAAa,CAAC,OAAO,EAAE,kBAAkB,EAAE,GAAG,IAAI;IAI5C,IAAI,CACR,gBAAgB,EAAE,CAAC,EACjB,KAAK,EACL,IAAI,GACL,EAAE;QACD,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,KAAK,IAAI,GACT,OAAO,CAAC,IAAI,CAAC;YAIF,eAAe;IAS7B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAW1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAuB1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAQ7B;;OAEG;YACW,qBAAqB;IAWnC;;OAEG;IACH,OAAO,CAAC,iBAAiB;YAwCX,aAAa;YAoDb,WAAW;IAiEzB,OAAO,CAAC,WAAW;IA6DnB,OAAO,CAAC,gBAAgB;YAsBV,UAAU;YA+CV,SAAS;IAevB,OAAO,CAAC,cAAc;CAGvB;AAED,eAAO,MAAM,cAAc,YACf,aAAa,aAAa,OAAO,CAAC,eAAe,CAAC,kBAE3D,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6719,20 +6719,36 @@ class RTCHost {
|
|
|
6719
6719
|
const payload = verifyToken(token);
|
|
6720
6720
|
return payload;
|
|
6721
6721
|
} catch (error) {
|
|
6722
|
-
console.error("Token verification failed:", error);
|
|
6723
6722
|
return null;
|
|
6724
6723
|
}
|
|
6725
6724
|
}
|
|
6726
|
-
tokenToAuthContext(payload) {
|
|
6725
|
+
tokenToAuthContext(payload, ipAddress) {
|
|
6727
6726
|
return {
|
|
6728
6727
|
userId: payload.userId,
|
|
6729
|
-
roles: []
|
|
6728
|
+
roles: [],
|
|
6729
|
+
ipAddress
|
|
6730
6730
|
};
|
|
6731
6731
|
}
|
|
6732
|
-
|
|
6732
|
+
getClientIpAddress(req) {
|
|
6733
|
+
const xForwardedFor = req.headers.get("x-forwarded-for");
|
|
6734
|
+
const xRealIp = req.headers.get("x-real-ip");
|
|
6735
|
+
const cfConnectingIp = req.headers.get("cf-connecting-ip");
|
|
6736
|
+
if (xForwardedFor) {
|
|
6737
|
+
return xForwardedFor.split(",")[0].trim();
|
|
6738
|
+
}
|
|
6739
|
+
if (xRealIp) {
|
|
6740
|
+
return xRealIp;
|
|
6741
|
+
}
|
|
6742
|
+
if (cfConnectingIp) {
|
|
6743
|
+
return cfConnectingIp;
|
|
6744
|
+
}
|
|
6745
|
+
return;
|
|
6746
|
+
}
|
|
6747
|
+
getDefaultAuthContext(ipAddress) {
|
|
6733
6748
|
return {
|
|
6734
6749
|
userId: "anonymous",
|
|
6735
|
-
roles: []
|
|
6750
|
+
roles: [],
|
|
6751
|
+
ipAddress
|
|
6736
6752
|
};
|
|
6737
6753
|
}
|
|
6738
6754
|
async parseFormDataToObject(formData) {
|
|
@@ -6784,15 +6800,16 @@ class RTCHost {
|
|
|
6784
6800
|
try {
|
|
6785
6801
|
const authHeader = req.headers.get("Authorization");
|
|
6786
6802
|
const token = authHeader?.replace("Bearer ", "");
|
|
6803
|
+
const clientIp = this.getClientIpAddress(req);
|
|
6787
6804
|
let authContext;
|
|
6788
6805
|
if (token && !this.isPublicEndpoint(url.pathname)) {
|
|
6789
6806
|
const payload = await this.verifyAuthToken(token);
|
|
6790
6807
|
if (!payload) {
|
|
6791
6808
|
return new Response("Invalid or expired token", { status: 401 });
|
|
6792
6809
|
}
|
|
6793
|
-
authContext = this.tokenToAuthContext(payload);
|
|
6810
|
+
authContext = this.tokenToAuthContext(payload, clientIp);
|
|
6794
6811
|
} else {
|
|
6795
|
-
authContext = this.getDefaultAuthContext();
|
|
6812
|
+
authContext = this.getDefaultAuthContext(clientIp);
|
|
6796
6813
|
}
|
|
6797
6814
|
let argument;
|
|
6798
6815
|
const contentType = req.headers.get("Content-Type");
|
|
@@ -6817,13 +6834,14 @@ class RTCHost {
|
|
|
6817
6834
|
try {
|
|
6818
6835
|
const authHeader = req.headers.get("Authorization");
|
|
6819
6836
|
const token = authHeader?.replace("Bearer ", "");
|
|
6837
|
+
const clientIp = this.getClientIpAddress(req);
|
|
6820
6838
|
let authContext;
|
|
6821
6839
|
if (token) {
|
|
6822
6840
|
const payload = await this.verifyAuthToken(token);
|
|
6823
6841
|
if (!payload) {
|
|
6824
6842
|
return new Response("Invalid or expired token", { status: 401 });
|
|
6825
6843
|
}
|
|
6826
|
-
authContext = this.tokenToAuthContext(payload);
|
|
6844
|
+
authContext = this.tokenToAuthContext(payload, clientIp);
|
|
6827
6845
|
} else {
|
|
6828
6846
|
return new Response("Authorization token required", { status: 401 });
|
|
6829
6847
|
}
|
|
@@ -6901,8 +6919,15 @@ class RTCHost {
|
|
|
6901
6919
|
});
|
|
6902
6920
|
}
|
|
6903
6921
|
isPublicEndpoint(pathname) {
|
|
6904
|
-
|
|
6905
|
-
|
|
6922
|
+
if (!pathname.startsWith("/command/")) {
|
|
6923
|
+
return false;
|
|
6924
|
+
}
|
|
6925
|
+
const commandName = pathname.split("/command/")[1];
|
|
6926
|
+
if (!commandName) {
|
|
6927
|
+
return false;
|
|
6928
|
+
}
|
|
6929
|
+
const contextElement = this.context.elements.find((element) => element.name === commandName);
|
|
6930
|
+
return contextElement && "isPublic" in contextElement ? contextElement.isPublic === true : false;
|
|
6906
6931
|
}
|
|
6907
6932
|
async handleSync(lastDate) {
|
|
6908
6933
|
const syncDate = new Date;
|
package/host.ts
CHANGED
|
@@ -53,7 +53,6 @@ class RTCHost implements RealTimeCommunicationAdapter {
|
|
|
53
53
|
const payload = verifyToken(token);
|
|
54
54
|
return payload;
|
|
55
55
|
} catch (error) {
|
|
56
|
-
console.error("Token verification failed:", error);
|
|
57
56
|
return null;
|
|
58
57
|
}
|
|
59
58
|
}
|
|
@@ -61,20 +60,51 @@ class RTCHost implements RealTimeCommunicationAdapter {
|
|
|
61
60
|
/**
|
|
62
61
|
* Convert JWT payload to AuthContext
|
|
63
62
|
*/
|
|
64
|
-
private tokenToAuthContext(
|
|
63
|
+
private tokenToAuthContext(
|
|
64
|
+
payload: TokenPayload,
|
|
65
|
+
ipAddress?: string,
|
|
66
|
+
): AuthContext {
|
|
65
67
|
return {
|
|
66
68
|
userId: payload.userId,
|
|
67
69
|
roles: [], // Default to no roles, you may want to extend TokenPayload to include roles
|
|
70
|
+
ipAddress,
|
|
68
71
|
};
|
|
69
72
|
}
|
|
70
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Extract client IP address from request headers
|
|
76
|
+
*/
|
|
77
|
+
private getClientIpAddress(req: Request): string | undefined {
|
|
78
|
+
// Check common headers for client IP
|
|
79
|
+
const xForwardedFor = req.headers.get("x-forwarded-for");
|
|
80
|
+
const xRealIp = req.headers.get("x-real-ip");
|
|
81
|
+
const cfConnectingIp = req.headers.get("cf-connecting-ip");
|
|
82
|
+
|
|
83
|
+
if (xForwardedFor) {
|
|
84
|
+
// x-forwarded-for can contain multiple IPs, take the first one
|
|
85
|
+
return xForwardedFor.split(",")[0].trim();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (xRealIp) {
|
|
89
|
+
return xRealIp;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (cfConnectingIp) {
|
|
93
|
+
return cfConnectingIp;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Fallback - this might not work in all environments
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
71
100
|
/**
|
|
72
101
|
* Get default auth context for anonymous users
|
|
73
102
|
*/
|
|
74
|
-
private getDefaultAuthContext(): AuthContext {
|
|
103
|
+
private getDefaultAuthContext(ipAddress?: string): AuthContext {
|
|
75
104
|
return {
|
|
76
105
|
userId: "anonymous",
|
|
77
106
|
roles: [],
|
|
107
|
+
ipAddress,
|
|
78
108
|
};
|
|
79
109
|
}
|
|
80
110
|
|
|
@@ -148,15 +178,16 @@ class RTCHost implements RealTimeCommunicationAdapter {
|
|
|
148
178
|
const authHeader = req.headers.get("Authorization");
|
|
149
179
|
const token = authHeader?.replace("Bearer ", "");
|
|
150
180
|
|
|
181
|
+
const clientIp = this.getClientIpAddress(req);
|
|
151
182
|
let authContext: AuthContext;
|
|
152
183
|
if (token && !this.isPublicEndpoint(url.pathname)) {
|
|
153
184
|
const payload = await this.verifyAuthToken(token);
|
|
154
185
|
if (!payload) {
|
|
155
186
|
return new Response("Invalid or expired token", { status: 401 });
|
|
156
187
|
}
|
|
157
|
-
authContext = this.tokenToAuthContext(payload);
|
|
188
|
+
authContext = this.tokenToAuthContext(payload, clientIp);
|
|
158
189
|
} else {
|
|
159
|
-
authContext = this.getDefaultAuthContext();
|
|
190
|
+
authContext = this.getDefaultAuthContext(clientIp);
|
|
160
191
|
}
|
|
161
192
|
|
|
162
193
|
let argument: any;
|
|
@@ -192,13 +223,14 @@ class RTCHost implements RealTimeCommunicationAdapter {
|
|
|
192
223
|
const authHeader = req.headers.get("Authorization");
|
|
193
224
|
const token = authHeader?.replace("Bearer ", "");
|
|
194
225
|
|
|
226
|
+
const clientIp = this.getClientIpAddress(req);
|
|
195
227
|
let authContext: AuthContext;
|
|
196
228
|
if (token) {
|
|
197
229
|
const payload = await this.verifyAuthToken(token);
|
|
198
230
|
if (!payload) {
|
|
199
231
|
return new Response("Invalid or expired token", { status: 401 });
|
|
200
232
|
}
|
|
201
|
-
authContext = this.tokenToAuthContext(payload);
|
|
233
|
+
authContext = this.tokenToAuthContext(payload, clientIp);
|
|
202
234
|
} else {
|
|
203
235
|
return new Response("Authorization token required", { status: 401 });
|
|
204
236
|
}
|
|
@@ -312,10 +344,25 @@ class RTCHost implements RealTimeCommunicationAdapter {
|
|
|
312
344
|
}
|
|
313
345
|
|
|
314
346
|
private isPublicEndpoint(pathname: string): boolean {
|
|
315
|
-
//
|
|
316
|
-
|
|
347
|
+
// Extract command name from pathname
|
|
348
|
+
if (!pathname.startsWith("/command/")) {
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const commandName = pathname.split("/command/")[1];
|
|
353
|
+
if (!commandName) {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Get the command from the context and check if it's marked as public
|
|
358
|
+
const contextElement = this.context.elements.find(
|
|
359
|
+
(element: any) => element.name === commandName,
|
|
360
|
+
);
|
|
317
361
|
|
|
318
|
-
|
|
362
|
+
// Check if it's an ArcCommand instance and if it's marked as public
|
|
363
|
+
return contextElement && "isPublic" in contextElement
|
|
364
|
+
? contextElement.isPublic === true
|
|
365
|
+
: false;
|
|
319
366
|
}
|
|
320
367
|
|
|
321
368
|
private async handleSync(lastDate: string | null) {
|