@obfious/js 0.1.1 → 0.1.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/README.md +55 -10
- package/dist/express.d.ts +5 -5
- package/dist/express.js +1 -1
- package/dist/fastify.d.ts +5 -5
- package/dist/fastify.js +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +1 -1
- package/dist/lambda.d.ts +5 -5
- package/dist/lambda.js +1 -1
- package/dist/nextjs.d.ts +6 -6
- package/dist/nextjs.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @obfious/js
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Anti-bot device intelligence for JavaScript — Cloudflare Workers, Next.js, Express, Fastify, Lambda.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -18,24 +18,26 @@ npm install @obfious/js
|
|
|
18
18
|
| `@obfious/js/fastify` | Fastify |
|
|
19
19
|
| `@obfious/js/lambda` | AWS Lambda (API Gateway) |
|
|
20
20
|
|
|
21
|
-
## Quick
|
|
21
|
+
## Quick start
|
|
22
22
|
|
|
23
23
|
```typescript
|
|
24
24
|
import { Obfious } from "@obfious/js";
|
|
25
25
|
|
|
26
26
|
const obfious = new Obfious({
|
|
27
|
-
|
|
27
|
+
stableString: "my-app:3000",
|
|
28
|
+
includePaths: ["/api/"],
|
|
28
29
|
});
|
|
29
30
|
|
|
31
|
+
const creds = { keyId: process.env.OBFIOUS_KEY_ID, secret: process.env.OBFIOUS_SECRET };
|
|
32
|
+
|
|
30
33
|
// In your request handler:
|
|
31
|
-
const result = await obfious.protect(request,
|
|
32
|
-
keyId: process.env.OBFIOUS_KEY_ID,
|
|
33
|
-
secret: process.env.OBFIOUS_SECRET,
|
|
34
|
-
});
|
|
34
|
+
const result = await obfious.protect(request, creds);
|
|
35
35
|
if (result.response) return result.response;
|
|
36
|
+
// result.deviceId is set when token is valid
|
|
36
37
|
|
|
37
|
-
//
|
|
38
|
-
|
|
38
|
+
// Script tag for HTML <head>:
|
|
39
|
+
const tag = await obfious.scriptTag({ nonce: "abc123" });
|
|
40
|
+
// → <script src="/a3f7c9d4e5.js" nonce="abc123" defer></script>
|
|
39
41
|
```
|
|
40
42
|
|
|
41
43
|
### Next.js
|
|
@@ -46,10 +48,11 @@ import { NextResponse } from "next/server";
|
|
|
46
48
|
|
|
47
49
|
const obfious = createObfiousMiddleware({
|
|
48
50
|
creds: { keyId: process.env.OBFIOUS_KEY_ID!, secret: process.env.OBFIOUS_SECRET! },
|
|
51
|
+
stableString: "my-nextjs-app",
|
|
49
52
|
includePaths: ["/api/"],
|
|
50
53
|
});
|
|
51
54
|
|
|
52
|
-
export async function middleware(request) {
|
|
55
|
+
export async function middleware(request: NextRequest) {
|
|
53
56
|
const response = await obfious(request);
|
|
54
57
|
if (response) return response;
|
|
55
58
|
return NextResponse.next();
|
|
@@ -65,10 +68,52 @@ import { obfiousMiddleware } from "@obfious/js/express";
|
|
|
65
68
|
const app = express();
|
|
66
69
|
app.use(obfiousMiddleware({
|
|
67
70
|
creds: { keyId: process.env.OBFIOUS_KEY_ID!, secret: process.env.OBFIOUS_SECRET! },
|
|
71
|
+
stableString: `my-app:${PORT}`,
|
|
68
72
|
includePaths: ["/api/"],
|
|
69
73
|
}));
|
|
70
74
|
```
|
|
71
75
|
|
|
76
|
+
### Fastify
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import Fastify from "fastify";
|
|
80
|
+
import { obfiousPlugin } from "@obfious/js/fastify";
|
|
81
|
+
|
|
82
|
+
const app = Fastify();
|
|
83
|
+
app.register(obfiousPlugin, {
|
|
84
|
+
creds: { keyId: process.env.OBFIOUS_KEY_ID!, secret: process.env.OBFIOUS_SECRET! },
|
|
85
|
+
stableString: `my-app:${PORT}`,
|
|
86
|
+
includePaths: ["/api/"],
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Lambda
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { obfiousHandler } from "@obfious/js/lambda";
|
|
94
|
+
|
|
95
|
+
export const handler = obfiousHandler({
|
|
96
|
+
creds: { keyId: process.env.OBFIOUS_KEY_ID!, secret: process.env.OBFIOUS_SECRET! },
|
|
97
|
+
stableString: "my-lambda-api",
|
|
98
|
+
includePaths: ["/api/"],
|
|
99
|
+
}, async (event, context) => {
|
|
100
|
+
return { statusCode: 200, body: JSON.stringify({ ok: true }), headers: {} };
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Configuration
|
|
105
|
+
|
|
106
|
+
| Option | Type | Default | Description |
|
|
107
|
+
|--------|------|---------|-------------|
|
|
108
|
+
| `apiUrl` | string | `https://api.obfious.com` | API base URL |
|
|
109
|
+
| `stableString` | string | `"obfious-default"` | Stable string for script path derivation |
|
|
110
|
+
| `scriptPath` | string | (derived) | Override the derived script path |
|
|
111
|
+
| `includePaths` | string[] | (all) | Only guard these path prefixes |
|
|
112
|
+
| `excludePaths` | string[] | (none) | Always pass through these prefixes |
|
|
113
|
+
| `privateKey` | string | — | HMAC key for user ID encryption |
|
|
114
|
+
| `getClientIp` | callback | (auto) | Custom client IP extraction |
|
|
115
|
+
| `getPlatformSignals` | callback | (CF default) | Custom platform signal headers |
|
|
116
|
+
|
|
72
117
|
## License
|
|
73
118
|
|
|
74
119
|
See LICENSE file.
|
package/dist/express.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
-
import {
|
|
3
|
-
export {
|
|
4
|
-
export interface
|
|
5
|
-
creds:
|
|
2
|
+
import { Obfious, ObfiousConfig, ObfiousCreds, ProtectResult } from "@obfious/js";
|
|
3
|
+
export { Obfious, ObfiousConfig, ObfiousCreds, ProtectResult };
|
|
4
|
+
export interface ObfiousExpressOptions extends ObfiousConfig {
|
|
5
|
+
creds: ObfiousCreds;
|
|
6
6
|
getUser?: (req: IncomingMessage) => string | undefined;
|
|
7
7
|
}
|
|
8
|
-
export declare function obfiousMiddleware(options:
|
|
8
|
+
export declare function obfiousMiddleware(options: ObfiousExpressOptions): (req: IncomingMessage, res: ServerResponse, next: (err?: any) => void) => Promise<void>;
|
package/dist/express.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var b="x-obfious-key",P="x-obfious-sig",v="x-obfious-ts",R=/\.(json|js|gif|png|woff2|css)$/,l=class{config;creds=null;scriptPathCache=null;constructor(e={}){this.config={...e,apiUrl:e.apiUrl??"https://api.obfious.com"}}async getScriptPath(){if(this.config.scriptPath)return this.config.scriptPath;if(this.scriptPathCache)return this.scriptPathCache;let e=this.config.stableString||"obfious-default";return this.scriptPathCache=await C(e),this.scriptPathCache}async scriptTag(e){let t=await this.getScriptPath(),s=e?.nonce?` nonce="${e.nonce}"`:"";return`<script src="${t}"${s} defer></script>`}async protect(e,t,s){let r={response:null};if(t&&!this.creds&&(this.creds=t),!this.creds)return r;let n=new URL(e.url);if(e.method==="GET"){let p=await this.getScriptPath();if(n.pathname===p){let u=await this.fetchBundle();if(u)return{response:new Response(u,{headers:{"Content-Type":"application/javascript","Cache-Control":"no-store"}})}}}if(e.method==="POST"&&R.test(n.pathname)){let p=e.clone(),u=new Uint8Array(await p.arrayBuffer());if(u.length>0&&u[0]===91)return{response:await this.forwardToApi(n.pathname,u)}}if(this.config.excludePaths?.some(p=>n.pathname.startsWith(p))||this.config.includePaths&&!this.config.includePaths.some(p=>n.pathname.startsWith(p)))return r;let a=e.headers.get("x-req-auth");if(!a)return{response:new Response(null,{status:401})};let o=a.indexOf(".");if(o<1)return{response:new Response(null,{status:401})};let c=a.slice(0,o),h=a.slice(o+1),d=A(c);if(!d)return{response:new Response(null,{status:401})};let w=s&&this.config.privateKey?await S(s,this.config.privateKey):void 0,f=await this.validateToken(d,c,h,w);return f.valid?{response:null,deviceId:f.deviceId}:{response:new Response(null,{status:401})}}getIp(e){return this.config.getClientIp?this.config.getClientIp(e):e.headers.get("CF-Connecting-IP")||e.headers.get("X-Forwarded-For")?.split(",")[0]?.trim()||e.headers.get("X-Real-IP")||"unknown"}async fetchBundle(){try{let e=await this.authedFetch("/b",{method:"GET"});return e.ok?await e.text():null}catch{return null}}async forwardToApi(e,t){return this.authedFetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:t.buffer})}async validateToken(e,t,s,r){try{let n={tokenHex:e,signature:s,payload:t};r&&(n.encryptedUser=r);let a=await this.authedFetch("/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});if(!a.ok)return{valid:!1};let o=await a.json();return{valid:o.valid===!0,deviceId:o.deviceId}}catch{return{valid:!1}}}async authedFetch(e,t){let s=`${this.config.apiUrl}${e}`,r=Date.now().toString(),n=(t.method||"GET").toUpperCase(),a=`${r}.${n}.${e}`,o=await x(this.creds.secret,a),c=new Headers(t.headers);return c.set(b,this.creds.keyId),c.set(P,o),c.set(v,r),fetch(s,{...t,headers:c})}};async function C(i){let e=await crypto.subtle.importKey("raw",new TextEncoder().encode("obfious-script-v1"),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),t=await crypto.subtle.sign("HMAC",e,new TextEncoder().encode(i));return`/${Array.from(new Uint8Array(t),r=>r.toString(16).padStart(2,"0")).join("").slice(0,10)}.js`}async function x(i,e){let t=new TextEncoder().encode(i),s=await crypto.subtle.importKey("raw",t,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),r=await crypto.subtle.sign("HMAC",s,new TextEncoder().encode(e));return Array.from(new Uint8Array(r),n=>n.toString(16).padStart(2,"0")).join("")}async function S(i,e){let t=new TextEncoder().encode(e),s=await crypto.subtle.importKey("raw",t,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),r=await crypto.subtle.sign("HMAC",s,new TextEncoder().encode(i));return Array.from(new Uint8Array(r),n=>n.toString(16).padStart(2,"0")).join("")}function A(i){try{let e=i.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4;)e+="=";let t=Uint8Array.from(atob(e),s=>s.charCodeAt(0));return t.length<9||t[0]!==33?null:Array.from(t.slice(1,9),s=>s.toString(16).padStart(2,"0")).join("")}catch{return null}}import{Readable as g}from"node:stream";function y(i){let e=i.headers["x-forwarded-proto"]||"http",t=i.headers.host||"localhost",s=`${e}://${t}${i.url}`,r=new Headers;for(let[a,o]of Object.entries(i.headers))o&&r.set(a,Array.isArray(o)?o.join(", "):o);let n=i.method!=="GET"&&i.method!=="HEAD";return new Request(s,{method:i.method,headers:r,body:n?g.toWeb(g.from(i)):null,duplex:"half"})}async function m(i,e){let t={};if(e.headers.forEach((s,r)=>{t[r]=s}),i.writeHead(e.status,t),e.body){let s=e.body.getReader();try{for(;;){let{done:r,value:n}=await s.read();if(r)break;i.write(n)}}finally{s.releaseLock()}}i.end()}function
|
|
1
|
+
var b="x-obfious-key",P="x-obfious-sig",v="x-obfious-ts",R=/\.(json|js|gif|png|woff2|css)$/,l=class{config;creds=null;scriptPathCache=null;constructor(e={}){this.config={...e,apiUrl:e.apiUrl??"https://api.obfious.com"}}async getScriptPath(){if(this.config.scriptPath)return this.config.scriptPath;if(this.scriptPathCache)return this.scriptPathCache;let e=this.config.stableString||"obfious-default";return this.scriptPathCache=await C(e),this.scriptPathCache}async scriptTag(e){let t=await this.getScriptPath(),s=e?.nonce?` nonce="${e.nonce}"`:"";return`<script src="${t}"${s} defer></script>`}async protect(e,t,s){let r={response:null};if(t&&!this.creds&&(this.creds=t),!this.creds)return r;let n=new URL(e.url);if(e.method==="GET"){let p=await this.getScriptPath();if(n.pathname===p){let u=await this.fetchBundle();if(u)return{response:new Response(u,{headers:{"Content-Type":"application/javascript","Cache-Control":"no-store"}})}}}if(e.method==="POST"&&R.test(n.pathname)){let p=e.clone(),u=new Uint8Array(await p.arrayBuffer());if(u.length>0&&u[0]===91)return{response:await this.forwardToApi(n.pathname,u)}}if(this.config.excludePaths?.some(p=>n.pathname.startsWith(p))||this.config.includePaths&&!this.config.includePaths.some(p=>n.pathname.startsWith(p)))return r;let a=e.headers.get("x-req-auth");if(!a)return{response:new Response(null,{status:401})};let o=a.indexOf(".");if(o<1)return{response:new Response(null,{status:401})};let c=a.slice(0,o),h=a.slice(o+1),d=A(c);if(!d)return{response:new Response(null,{status:401})};let w=s&&this.config.privateKey?await S(s,this.config.privateKey):void 0,f=await this.validateToken(d,c,h,w);return f.valid?{response:null,deviceId:f.deviceId}:{response:new Response(null,{status:401})}}getIp(e){return this.config.getClientIp?this.config.getClientIp(e):e.headers.get("CF-Connecting-IP")||e.headers.get("X-Forwarded-For")?.split(",")[0]?.trim()||e.headers.get("X-Real-IP")||"unknown"}async fetchBundle(){try{let e=await this.authedFetch("/b",{method:"GET"});return e.ok?await e.text():null}catch{return null}}async forwardToApi(e,t){return this.authedFetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:t.buffer})}async validateToken(e,t,s,r){try{let n={tokenHex:e,signature:s,payload:t};r&&(n.encryptedUser=r);let a=await this.authedFetch("/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});if(!a.ok)return{valid:!1};let o=await a.json();return{valid:o.valid===!0,deviceId:o.deviceId}}catch{return{valid:!1}}}async authedFetch(e,t){let s=`${this.config.apiUrl}${e}`,r=Date.now().toString(),n=(t.method||"GET").toUpperCase(),a=`${r}.${n}.${e}`,o=await x(this.creds.secret,a),c=new Headers(t.headers);return c.set(b,this.creds.keyId),c.set(P,o),c.set(v,r),fetch(s,{...t,headers:c})}};async function C(i){let e=await crypto.subtle.importKey("raw",new TextEncoder().encode("obfious-script-v1"),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),t=await crypto.subtle.sign("HMAC",e,new TextEncoder().encode(i));return`/${Array.from(new Uint8Array(t),r=>r.toString(16).padStart(2,"0")).join("").slice(0,10)}.js`}async function x(i,e){let t=new TextEncoder().encode(i),s=await crypto.subtle.importKey("raw",t,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),r=await crypto.subtle.sign("HMAC",s,new TextEncoder().encode(e));return Array.from(new Uint8Array(r),n=>n.toString(16).padStart(2,"0")).join("")}async function S(i,e){let t=new TextEncoder().encode(e),s=await crypto.subtle.importKey("raw",t,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),r=await crypto.subtle.sign("HMAC",s,new TextEncoder().encode(i));return Array.from(new Uint8Array(r),n=>n.toString(16).padStart(2,"0")).join("")}function A(i){try{let e=i.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4;)e+="=";let t=Uint8Array.from(atob(e),s=>s.charCodeAt(0));return t.length<9||t[0]!==33?null:Array.from(t.slice(1,9),s=>s.toString(16).padStart(2,"0")).join("")}catch{return null}}import{Readable as g}from"node:stream";function y(i){let e=i.headers["x-forwarded-proto"]||"http",t=i.headers.host||"localhost",s=`${e}://${t}${i.url}`,r=new Headers;for(let[a,o]of Object.entries(i.headers))o&&r.set(a,Array.isArray(o)?o.join(", "):o);let n=i.method!=="GET"&&i.method!=="HEAD";return new Request(s,{method:i.method,headers:r,body:n?g.toWeb(g.from(i)):null,duplex:"half"})}async function m(i,e){let t={};if(e.headers.forEach((s,r)=>{t[r]=s}),i.writeHead(e.status,t),e.body){let s=e.body.getReader();try{for(;;){let{done:r,value:n}=await s.read();if(r)break;i.write(n)}}finally{s.releaseLock()}}i.end()}function E(i){let{creds:e,getUser:t,...s}=i,r=new l({...s,getClientIp:s.getClientIp??(n=>n.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||n.headers.get("x-real-ip")||"unknown"),getPlatformSignals:s.getPlatformSignals??(()=>({}))});return async(n,a,o)=>{try{let c=y(n),h=t?.(n),d=await r.protect(c,e,h);if(d.response){await m(a,d.response);return}d.deviceId&&(n.obfiousDeviceId=d.deviceId),o()}catch(c){o(c)}}}export{l as Obfious,E as obfiousMiddleware};
|
package/dist/fastify.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { IncomingMessage } from "node:http";
|
|
2
|
-
import {
|
|
3
|
-
export {
|
|
4
|
-
export interface
|
|
5
|
-
creds:
|
|
2
|
+
import { Obfious, ObfiousConfig, ObfiousCreds, ProtectResult } from "@obfious/js";
|
|
3
|
+
export { Obfious, ObfiousConfig, ObfiousCreds, ProtectResult };
|
|
4
|
+
export interface ObfiousFastifyOptions extends ObfiousConfig {
|
|
5
|
+
creds: ObfiousCreds;
|
|
6
6
|
getUser?: (req: IncomingMessage) => string | undefined;
|
|
7
7
|
}
|
|
8
|
-
export declare function obfiousPlugin(fastify: any, options:
|
|
8
|
+
export declare function obfiousPlugin(fastify: any, options: ObfiousFastifyOptions): Promise<void>;
|
package/dist/fastify.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var w="x-obfious-key",b="x-obfious-sig",P="x-obfious-ts",R=/\.(json|js|gif|png|woff2|css)$/,f=class{config;creds=null;scriptPathCache=null;constructor(t={}){this.config={...t,apiUrl:t.apiUrl??"https://api.obfious.com"}}async getScriptPath(){if(this.config.scriptPath)return this.config.scriptPath;if(this.scriptPathCache)return this.scriptPathCache;let t=this.config.stableString||"obfious-default";return this.scriptPathCache=await v(t),this.scriptPathCache}async scriptTag(t){let e=await this.getScriptPath(),n=t?.nonce?` nonce="${t.nonce}"`:"";return`<script src="${e}"${n} defer></script>`}async protect(t,e,n){let s={response:null};if(e&&!this.creds&&(this.creds=e),!this.creds)return s;let i=new URL(t.url);if(t.method==="GET"){let u=await this.getScriptPath();if(i.pathname===u){let p=await this.fetchBundle();if(p)return{response:new Response(p,{headers:{"Content-Type":"application/javascript","Cache-Control":"no-store"}})}}}if(t.method==="POST"&&R.test(i.pathname)){let u=t.clone(),p=new Uint8Array(await u.arrayBuffer());if(p.length>0&&p[0]===91)return{response:await this.forwardToApi(i.pathname,p)}}if(this.config.excludePaths?.some(u=>i.pathname.startsWith(u))||this.config.includePaths&&!this.config.includePaths.some(u=>i.pathname.startsWith(u)))return s;let o=t.headers.get("x-req-auth");if(!o)return{response:new Response(null,{status:401})};let a=o.indexOf(".");if(a<1)return{response:new Response(null,{status:401})};let c=o.slice(0,a),g=o.slice(a+1),d=S(c);if(!d)return{response:new Response(null,{status:401})};let h=n&&this.config.privateKey?await x(n,this.config.privateKey):void 0,l=await this.validateToken(d,c,g,h);return l.valid?{response:null,deviceId:l.deviceId}:{response:new Response(null,{status:401})}}getIp(t){return this.config.getClientIp?this.config.getClientIp(t):t.headers.get("CF-Connecting-IP")||t.headers.get("X-Forwarded-For")?.split(",")[0]?.trim()||t.headers.get("X-Real-IP")||"unknown"}async fetchBundle(){try{let t=await this.authedFetch("/b",{method:"GET"});return t.ok?await t.text():null}catch{return null}}async forwardToApi(t,e){return this.authedFetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:e.buffer})}async validateToken(t,e,n,s){try{let i={tokenHex:t,signature:n,payload:e};s&&(i.encryptedUser=s);let o=await this.authedFetch("/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!o.ok)return{valid:!1};let a=await o.json();return{valid:a.valid===!0,deviceId:a.deviceId}}catch{return{valid:!1}}}async authedFetch(t,e){let n=`${this.config.apiUrl}${t}`,s=Date.now().toString(),i=(e.method||"GET").toUpperCase(),o=`${s}.${i}.${t}`,a=await C(this.creds.secret,o),c=new Headers(e.headers);return c.set(w,this.creds.keyId),c.set(b,a),c.set(P,s),fetch(n,{...e,headers:c})}};async function v(r){let t=await crypto.subtle.importKey("raw",new TextEncoder().encode("obfious-script-v1"),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),e=await crypto.subtle.sign("HMAC",t,new TextEncoder().encode(r));return`/${Array.from(new Uint8Array(e),s=>s.toString(16).padStart(2,"0")).join("").slice(0,10)}.js`}async function C(r,t){let e=new TextEncoder().encode(r),n=await crypto.subtle.importKey("raw",e,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(t));return Array.from(new Uint8Array(s),i=>i.toString(16).padStart(2,"0")).join("")}async function x(r,t){let e=new TextEncoder().encode(t),n=await crypto.subtle.importKey("raw",e,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(r));return Array.from(new Uint8Array(s),i=>i.toString(16).padStart(2,"0")).join("")}function S(r){try{let t=r.replace(/-/g,"+").replace(/_/g,"/");for(;t.length%4;)t+="=";let e=Uint8Array.from(atob(t),n=>n.charCodeAt(0));return e.length<9||e[0]!==33?null:Array.from(e.slice(1,9),n=>n.toString(16).padStart(2,"0")).join("")}catch{return null}}import{Readable as y}from"node:stream";function m(r){let t=r.headers["x-forwarded-proto"]||"http",e=r.headers.host||"localhost",n=`${t}://${e}${r.url}`,s=new Headers;for(let[o,a]of Object.entries(r.headers))a&&s.set(o,Array.isArray(a)?a.join(", "):a);let i=r.method!=="GET"&&r.method!=="HEAD";return new Request(n,{method:r.method,headers:s,body:i?y.toWeb(y.from(r)):null,duplex:"half"})}async function
|
|
1
|
+
var w="x-obfious-key",b="x-obfious-sig",P="x-obfious-ts",R=/\.(json|js|gif|png|woff2|css)$/,f=class{config;creds=null;scriptPathCache=null;constructor(t={}){this.config={...t,apiUrl:t.apiUrl??"https://api.obfious.com"}}async getScriptPath(){if(this.config.scriptPath)return this.config.scriptPath;if(this.scriptPathCache)return this.scriptPathCache;let t=this.config.stableString||"obfious-default";return this.scriptPathCache=await v(t),this.scriptPathCache}async scriptTag(t){let e=await this.getScriptPath(),n=t?.nonce?` nonce="${t.nonce}"`:"";return`<script src="${e}"${n} defer></script>`}async protect(t,e,n){let s={response:null};if(e&&!this.creds&&(this.creds=e),!this.creds)return s;let i=new URL(t.url);if(t.method==="GET"){let u=await this.getScriptPath();if(i.pathname===u){let p=await this.fetchBundle();if(p)return{response:new Response(p,{headers:{"Content-Type":"application/javascript","Cache-Control":"no-store"}})}}}if(t.method==="POST"&&R.test(i.pathname)){let u=t.clone(),p=new Uint8Array(await u.arrayBuffer());if(p.length>0&&p[0]===91)return{response:await this.forwardToApi(i.pathname,p)}}if(this.config.excludePaths?.some(u=>i.pathname.startsWith(u))||this.config.includePaths&&!this.config.includePaths.some(u=>i.pathname.startsWith(u)))return s;let o=t.headers.get("x-req-auth");if(!o)return{response:new Response(null,{status:401})};let a=o.indexOf(".");if(a<1)return{response:new Response(null,{status:401})};let c=o.slice(0,a),g=o.slice(a+1),d=S(c);if(!d)return{response:new Response(null,{status:401})};let h=n&&this.config.privateKey?await x(n,this.config.privateKey):void 0,l=await this.validateToken(d,c,g,h);return l.valid?{response:null,deviceId:l.deviceId}:{response:new Response(null,{status:401})}}getIp(t){return this.config.getClientIp?this.config.getClientIp(t):t.headers.get("CF-Connecting-IP")||t.headers.get("X-Forwarded-For")?.split(",")[0]?.trim()||t.headers.get("X-Real-IP")||"unknown"}async fetchBundle(){try{let t=await this.authedFetch("/b",{method:"GET"});return t.ok?await t.text():null}catch{return null}}async forwardToApi(t,e){return this.authedFetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:e.buffer})}async validateToken(t,e,n,s){try{let i={tokenHex:t,signature:n,payload:e};s&&(i.encryptedUser=s);let o=await this.authedFetch("/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!o.ok)return{valid:!1};let a=await o.json();return{valid:a.valid===!0,deviceId:a.deviceId}}catch{return{valid:!1}}}async authedFetch(t,e){let n=`${this.config.apiUrl}${t}`,s=Date.now().toString(),i=(e.method||"GET").toUpperCase(),o=`${s}.${i}.${t}`,a=await C(this.creds.secret,o),c=new Headers(e.headers);return c.set(w,this.creds.keyId),c.set(b,a),c.set(P,s),fetch(n,{...e,headers:c})}};async function v(r){let t=await crypto.subtle.importKey("raw",new TextEncoder().encode("obfious-script-v1"),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),e=await crypto.subtle.sign("HMAC",t,new TextEncoder().encode(r));return`/${Array.from(new Uint8Array(e),s=>s.toString(16).padStart(2,"0")).join("").slice(0,10)}.js`}async function C(r,t){let e=new TextEncoder().encode(r),n=await crypto.subtle.importKey("raw",e,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(t));return Array.from(new Uint8Array(s),i=>i.toString(16).padStart(2,"0")).join("")}async function x(r,t){let e=new TextEncoder().encode(t),n=await crypto.subtle.importKey("raw",e,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(r));return Array.from(new Uint8Array(s),i=>i.toString(16).padStart(2,"0")).join("")}function S(r){try{let t=r.replace(/-/g,"+").replace(/_/g,"/");for(;t.length%4;)t+="=";let e=Uint8Array.from(atob(t),n=>n.charCodeAt(0));return e.length<9||e[0]!==33?null:Array.from(e.slice(1,9),n=>n.toString(16).padStart(2,"0")).join("")}catch{return null}}import{Readable as y}from"node:stream";function m(r){let t=r.headers["x-forwarded-proto"]||"http",e=r.headers.host||"localhost",n=`${t}://${e}${r.url}`,s=new Headers;for(let[o,a]of Object.entries(r.headers))a&&s.set(o,Array.isArray(a)?a.join(", "):a);let i=r.method!=="GET"&&r.method!=="HEAD";return new Request(n,{method:r.method,headers:s,body:i?y.toWeb(y.from(r)):null,duplex:"half"})}async function k(r,t){let{creds:e,getUser:n,...s}=t,i=new f({...s,getClientIp:s.getClientIp??(o=>o.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||o.headers.get("x-real-ip")||"unknown"),getPlatformSignals:s.getPlatformSignals??(()=>({}))});r.addHook("onRequest",async(o,a)=>{let c=m(o.raw),g=n?.(o.raw),d=await i.protect(c,e,g);if(d.response){let h={};d.response.headers.forEach((u,p)=>{h[p]=u});let l=await d.response.text();a.code(d.response.status).headers(h).send(l);return}d.deviceId&&(o.obfiousDeviceId=d.deviceId)})}export{f as Obfious,k as obfiousPlugin};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface ObfiousConfig {
|
|
2
2
|
apiUrl?: string;
|
|
3
3
|
stableString?: string;
|
|
4
4
|
scriptPath?: string;
|
|
@@ -8,17 +8,17 @@ export interface ObfiousConfigV2 {
|
|
|
8
8
|
getClientIp?: (request: Request) => string;
|
|
9
9
|
getPlatformSignals?: (request: Request) => Record<string, string>;
|
|
10
10
|
}
|
|
11
|
-
export interface
|
|
11
|
+
export interface ObfiousCreds {
|
|
12
12
|
keyId: string;
|
|
13
13
|
secret: string;
|
|
14
14
|
}
|
|
15
|
-
export interface
|
|
15
|
+
export interface ProtectResult {
|
|
16
16
|
response: Response | null;
|
|
17
17
|
deviceId?: string;
|
|
18
18
|
}
|
|
19
|
-
export declare class
|
|
20
|
-
constructor(config?:
|
|
19
|
+
export declare class Obfious {
|
|
20
|
+
constructor(config?: ObfiousConfig);
|
|
21
21
|
getScriptPath(): Promise<string>;
|
|
22
22
|
scriptTag(opts?: { nonce?: string }): Promise<string>;
|
|
23
|
-
protect(request: Request, creds?:
|
|
23
|
+
protect(request: Request, creds?: ObfiousCreds, user?: string): Promise<ProtectResult>;
|
|
24
24
|
}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var y="x-obfious-key",w="x-obfious-sig",m="x-obfious-ts",P=/\.(json|js|gif|png|woff2|css)$/,u=class{config;creds=null;scriptPathCache=null;constructor(t={}){this.config={...t,apiUrl:t.apiUrl??"https://api.obfious.com"}}async getScriptPath(){if(this.config.scriptPath)return this.config.scriptPath;if(this.scriptPathCache)return this.scriptPathCache;let t=this.config.stableString||"obfious-default";return this.scriptPathCache=await b(t),this.scriptPathCache}async scriptTag(t){let e=await this.getScriptPath(),n=t?.nonce?` nonce="${t.nonce}"`:"";return`<script src="${e}"${n} defer></script>`}async protect(t,e,n){let s={response:null};if(e&&!this.creds&&(this.creds=e),!this.creds)return s;let r=new URL(t.url);if(t.method==="GET"){let h=await this.getScriptPath();if(r.pathname===h){let l=await this.fetchBundle();if(l)return{response:new Response(l,{headers:{"Content-Type":"application/javascript","Cache-Control":"no-store"}})}}}if(t.method==="POST"&&P.test(r.pathname)){let h=t.clone(),l=new Uint8Array(await h.arrayBuffer());if(l.length>0&&l[0]===91)return{response:await this.forwardToApi(r.pathname,l)}}if(this.config.excludePaths?.some(h=>r.pathname.startsWith(h))||this.config.includePaths&&!this.config.includePaths.some(h=>r.pathname.startsWith(h)))return s;let i=t.headers.get("x-req-auth");if(!i)return{response:new Response(null,{status:401})};let o=i.indexOf(".");if(o<1)return{response:new Response(null,{status:401})};let c=i.slice(0,o),g=i.slice(o+1),p=x(c);if(!p)return{response:new Response(null,{status:401})};let f=n&&this.config.privateKey?await v(n,this.config.privateKey):void 0,d=await this.validateToken(p,c,g,f);return d.valid?{response:null,deviceId:d.deviceId}:{response:new Response(null,{status:401})}}getIp(t){return this.config.getClientIp?this.config.getClientIp(t):t.headers.get("CF-Connecting-IP")||t.headers.get("X-Forwarded-For")?.split(",")[0]?.trim()||t.headers.get("X-Real-IP")||"unknown"}async fetchBundle(){try{let t=await this.authedFetch("/b",{method:"GET"});return t.ok?await t.text():null}catch{return null}}async forwardToApi(t,e){return this.authedFetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:e.buffer})}async validateToken(t,e,n,s){try{let r={tokenHex:t,signature:n,payload:e};s&&(r.encryptedUser=s);let i=await this.authedFetch("/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!i.ok)return{valid:!1};let o=await i.json();return{valid:o.valid===!0,deviceId:o.deviceId}}catch{return{valid:!1}}}async authedFetch(t,e){let n=`${this.config.apiUrl}${t}`,s=Date.now().toString(),r=(e.method||"GET").toUpperCase(),i=`${s}.${r}.${t}`,o=await C(this.creds.secret,i),c=new Headers(e.headers);return c.set(y,this.creds.keyId),c.set(w,o),c.set(m,s),fetch(n,{...e,headers:c})}};async function b(a){let t=await crypto.subtle.importKey("raw",new TextEncoder().encode("obfious-script-v1"),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),e=await crypto.subtle.sign("HMAC",t,new TextEncoder().encode(a));return`/${Array.from(new Uint8Array(e),s=>s.toString(16).padStart(2,"0")).join("").slice(0,10)}.js`}async function C(a,t){let e=new TextEncoder().encode(a),n=await crypto.subtle.importKey("raw",e,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(t));return Array.from(new Uint8Array(s),r=>r.toString(16).padStart(2,"0")).join("")}async function v(a,t){let e=new TextEncoder().encode(t),n=await crypto.subtle.importKey("raw",e,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(a));return Array.from(new Uint8Array(s),r=>r.toString(16).padStart(2,"0")).join("")}function x(a){try{let t=a.replace(/-/g,"+").replace(/_/g,"/");for(;t.length%4;)t+="=";let e=Uint8Array.from(atob(t),n=>n.charCodeAt(0));return e.length<9||e[0]!==33?null:Array.from(e.slice(1,9),n=>n.toString(16).padStart(2,"0")).join("")}catch{return null}}export{u as
|
|
1
|
+
var y="x-obfious-key",w="x-obfious-sig",m="x-obfious-ts",P=/\.(json|js|gif|png|woff2|css)$/,u=class{config;creds=null;scriptPathCache=null;constructor(t={}){this.config={...t,apiUrl:t.apiUrl??"https://api.obfious.com"}}async getScriptPath(){if(this.config.scriptPath)return this.config.scriptPath;if(this.scriptPathCache)return this.scriptPathCache;let t=this.config.stableString||"obfious-default";return this.scriptPathCache=await b(t),this.scriptPathCache}async scriptTag(t){let e=await this.getScriptPath(),n=t?.nonce?` nonce="${t.nonce}"`:"";return`<script src="${e}"${n} defer></script>`}async protect(t,e,n){let s={response:null};if(e&&!this.creds&&(this.creds=e),!this.creds)return s;let r=new URL(t.url);if(t.method==="GET"){let h=await this.getScriptPath();if(r.pathname===h){let l=await this.fetchBundle();if(l)return{response:new Response(l,{headers:{"Content-Type":"application/javascript","Cache-Control":"no-store"}})}}}if(t.method==="POST"&&P.test(r.pathname)){let h=t.clone(),l=new Uint8Array(await h.arrayBuffer());if(l.length>0&&l[0]===91)return{response:await this.forwardToApi(r.pathname,l)}}if(this.config.excludePaths?.some(h=>r.pathname.startsWith(h))||this.config.includePaths&&!this.config.includePaths.some(h=>r.pathname.startsWith(h)))return s;let i=t.headers.get("x-req-auth");if(!i)return{response:new Response(null,{status:401})};let o=i.indexOf(".");if(o<1)return{response:new Response(null,{status:401})};let c=i.slice(0,o),g=i.slice(o+1),p=x(c);if(!p)return{response:new Response(null,{status:401})};let f=n&&this.config.privateKey?await v(n,this.config.privateKey):void 0,d=await this.validateToken(p,c,g,f);return d.valid?{response:null,deviceId:d.deviceId}:{response:new Response(null,{status:401})}}getIp(t){return this.config.getClientIp?this.config.getClientIp(t):t.headers.get("CF-Connecting-IP")||t.headers.get("X-Forwarded-For")?.split(",")[0]?.trim()||t.headers.get("X-Real-IP")||"unknown"}async fetchBundle(){try{let t=await this.authedFetch("/b",{method:"GET"});return t.ok?await t.text():null}catch{return null}}async forwardToApi(t,e){return this.authedFetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:e.buffer})}async validateToken(t,e,n,s){try{let r={tokenHex:t,signature:n,payload:e};s&&(r.encryptedUser=s);let i=await this.authedFetch("/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!i.ok)return{valid:!1};let o=await i.json();return{valid:o.valid===!0,deviceId:o.deviceId}}catch{return{valid:!1}}}async authedFetch(t,e){let n=`${this.config.apiUrl}${t}`,s=Date.now().toString(),r=(e.method||"GET").toUpperCase(),i=`${s}.${r}.${t}`,o=await C(this.creds.secret,i),c=new Headers(e.headers);return c.set(y,this.creds.keyId),c.set(w,o),c.set(m,s),fetch(n,{...e,headers:c})}};async function b(a){let t=await crypto.subtle.importKey("raw",new TextEncoder().encode("obfious-script-v1"),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),e=await crypto.subtle.sign("HMAC",t,new TextEncoder().encode(a));return`/${Array.from(new Uint8Array(e),s=>s.toString(16).padStart(2,"0")).join("").slice(0,10)}.js`}async function C(a,t){let e=new TextEncoder().encode(a),n=await crypto.subtle.importKey("raw",e,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(t));return Array.from(new Uint8Array(s),r=>r.toString(16).padStart(2,"0")).join("")}async function v(a,t){let e=new TextEncoder().encode(t),n=await crypto.subtle.importKey("raw",e,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(a));return Array.from(new Uint8Array(s),r=>r.toString(16).padStart(2,"0")).join("")}function x(a){try{let t=a.replace(/-/g,"+").replace(/_/g,"/");for(;t.length%4;)t+="=";let e=Uint8Array.from(atob(t),n=>n.charCodeAt(0));return e.length<9||e[0]!==33?null:Array.from(e.slice(1,9),n=>n.toString(16).padStart(2,"0")).join("")}catch{return null}}export{u as Obfious};
|
package/dist/lambda.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { Obfious, ObfiousConfig, ObfiousCreds, ProtectResult } from "@obfious/js";
|
|
2
|
+
export { Obfious, ObfiousConfig, ObfiousCreds, ProtectResult };
|
|
3
3
|
export interface APIGatewayProxyEvent {
|
|
4
4
|
httpMethod: string;
|
|
5
5
|
path: string;
|
|
@@ -17,8 +17,8 @@ export interface APIGatewayProxyResult {
|
|
|
17
17
|
isBase64Encoded?: boolean;
|
|
18
18
|
}
|
|
19
19
|
export type LambdaHandler = (event: APIGatewayProxyEvent, context: any) => Promise<APIGatewayProxyResult>;
|
|
20
|
-
export interface
|
|
21
|
-
creds:
|
|
20
|
+
export interface ObfiousLambdaOptions extends ObfiousConfig {
|
|
21
|
+
creds: ObfiousCreds;
|
|
22
22
|
getUser?: (event: APIGatewayProxyEvent) => string | undefined;
|
|
23
23
|
}
|
|
24
|
-
export declare function obfiousHandler(options:
|
|
24
|
+
export declare function obfiousHandler(options: ObfiousLambdaOptions, handler: LambdaHandler): LambdaHandler;
|
package/dist/lambda.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var y="x-obfious-key",m="x-obfious-sig",w="x-obfious-ts",b=/\.(json|js|gif|png|woff2|css)$/,g=class{config;creds=null;scriptPathCache=null;constructor(t={}){this.config={...t,apiUrl:t.apiUrl??"https://api.obfious.com"}}async getScriptPath(){if(this.config.scriptPath)return this.config.scriptPath;if(this.scriptPathCache)return this.scriptPathCache;let t=this.config.stableString||"obfious-default";return this.scriptPathCache=await P(t),this.scriptPathCache}async scriptTag(t){let s=await this.getScriptPath(),r=t?.nonce?` nonce="${t.nonce}"`:"";return`<script src="${s}"${r} defer></script>`}async protect(t,s,r){let n={response:null};if(s&&!this.creds&&(this.creds=s),!this.creds)return n;let o=new URL(t.url);if(t.method==="GET"){let u=await this.getScriptPath();if(o.pathname===u){let h=await this.fetchBundle();if(h)return{response:new Response(h,{headers:{"Content-Type":"application/javascript","Cache-Control":"no-store"}})}}}if(t.method==="POST"&&b.test(o.pathname)){let u=t.clone(),h=new Uint8Array(await u.arrayBuffer());if(h.length>0&&h[0]===91)return{response:await this.forwardToApi(o.pathname,h)}}if(this.config.excludePaths?.some(u=>o.pathname.startsWith(u))||this.config.includePaths&&!this.config.includePaths.some(u=>o.pathname.startsWith(u)))return n;let i=t.headers.get("x-req-auth");if(!i)return{response:new Response(null,{status:401})};let c=i.indexOf(".");if(c<1)return{response:new Response(null,{status:401})};let a=i.slice(0,c),p=i.slice(c+1),d=R(a);if(!d)return{response:new Response(null,{status:401})};let l=r&&this.config.privateKey?await C(r,this.config.privateKey):void 0,f=await this.validateToken(d,a,p,l);return f.valid?{response:null,deviceId:f.deviceId}:{response:new Response(null,{status:401})}}getIp(t){return this.config.getClientIp?this.config.getClientIp(t):t.headers.get("CF-Connecting-IP")||t.headers.get("X-Forwarded-For")?.split(",")[0]?.trim()||t.headers.get("X-Real-IP")||"unknown"}async fetchBundle(){try{let t=await this.authedFetch("/b",{method:"GET"});return t.ok?await t.text():null}catch{return null}}async forwardToApi(t,s){return this.authedFetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:s.buffer})}async validateToken(t,s,r,n){try{let o={tokenHex:t,signature:r,payload:s};n&&(o.encryptedUser=n);let i=await this.authedFetch("/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)});if(!i.ok)return{valid:!1};let c=await i.json();return{valid:c.valid===!0,deviceId:c.deviceId}}catch{return{valid:!1}}}async authedFetch(t,s){let r=`${this.config.apiUrl}${t}`,n=Date.now().toString(),o=(s.method||"GET").toUpperCase(),i=`${n}.${o}.${t}`,c=await x(this.creds.secret,i),a=new Headers(s.headers);return a.set(y,this.creds.keyId),a.set(m,c),a.set(w,n),fetch(r,{...s,headers:a})}};async function P(e){let t=await crypto.subtle.importKey("raw",new TextEncoder().encode("obfious-script-v1"),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",t,new TextEncoder().encode(e));return`/${Array.from(new Uint8Array(s),n=>n.toString(16).padStart(2,"0")).join("").slice(0,10)}.js`}async function x(e,t){let s=new TextEncoder().encode(e),r=await crypto.subtle.importKey("raw",s,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),n=await crypto.subtle.sign("HMAC",r,new TextEncoder().encode(t));return Array.from(new Uint8Array(n),o=>o.toString(16).padStart(2,"0")).join("")}async function C(e,t){let s=new TextEncoder().encode(t),r=await crypto.subtle.importKey("raw",s,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),n=await crypto.subtle.sign("HMAC",r,new TextEncoder().encode(e));return Array.from(new Uint8Array(n),o=>o.toString(16).padStart(2,"0")).join("")}function R(e){try{let t=e.replace(/-/g,"+").replace(/_/g,"/");for(;t.length%4;)t+="=";let s=Uint8Array.from(atob(t),r=>r.charCodeAt(0));return s.length<9||s[0]!==33?null:Array.from(s.slice(1,9),r=>r.toString(16).padStart(2,"0")).join("")}catch{return null}}function S(e){let t=e.headers["x-forwarded-proto"]||e.headers["X-Forwarded-Proto"]||"https",s=e.headers.host||e.headers.Host||"localhost",r=`${t}://${s}${e.path}`;if(e.queryStringParameters){let c=new URLSearchParams;for(let[p,d]of Object.entries(e.queryStringParameters))d!=null&&c.set(p,d);let a=c.toString();a&&(r+=`?${a}`)}let n=new Headers;for(let[c,a]of Object.entries(e.headers))a&&n.set(c,a);let i=e.httpMethod!=="GET"&&e.httpMethod!=="HEAD"&&e.body!=null?e.isBase64Encoded?atob(e.body):e.body:null;return new Request(r,{method:e.httpMethod,headers:n,body:i})}async function A(e){let t={};return e.headers.forEach((s,r)=>{t[r]=s}),{statusCode:e.status,headers:t,body:await e.text()}}function H(e,t){let{creds:s,getUser:r,...n}=e,o=new g({...n,getClientIp:n.getClientIp??(i=>i.headers.get("x-lambda-source-ip")||i.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||"unknown"),getPlatformSignals:n.getPlatformSignals??(()=>({}))});return async(i,c)=>{let a=S(i),p=i.requestContext?.identity?.sourceIp||i.headers["x-forwarded-for"]?.split(",")[0]?.trim()||"unknown";a.headers.set("x-lambda-source-ip",p);let d=r?.(i),l=await o.protect(a,s,d);return l.response?A(l.response):(l.deviceId&&(i.headers["x-obfious-device-id"]=String(l.deviceId)),t(i,c))}}export{g as
|
|
1
|
+
var y="x-obfious-key",m="x-obfious-sig",w="x-obfious-ts",b=/\.(json|js|gif|png|woff2|css)$/,g=class{config;creds=null;scriptPathCache=null;constructor(t={}){this.config={...t,apiUrl:t.apiUrl??"https://api.obfious.com"}}async getScriptPath(){if(this.config.scriptPath)return this.config.scriptPath;if(this.scriptPathCache)return this.scriptPathCache;let t=this.config.stableString||"obfious-default";return this.scriptPathCache=await P(t),this.scriptPathCache}async scriptTag(t){let s=await this.getScriptPath(),r=t?.nonce?` nonce="${t.nonce}"`:"";return`<script src="${s}"${r} defer></script>`}async protect(t,s,r){let n={response:null};if(s&&!this.creds&&(this.creds=s),!this.creds)return n;let o=new URL(t.url);if(t.method==="GET"){let u=await this.getScriptPath();if(o.pathname===u){let h=await this.fetchBundle();if(h)return{response:new Response(h,{headers:{"Content-Type":"application/javascript","Cache-Control":"no-store"}})}}}if(t.method==="POST"&&b.test(o.pathname)){let u=t.clone(),h=new Uint8Array(await u.arrayBuffer());if(h.length>0&&h[0]===91)return{response:await this.forwardToApi(o.pathname,h)}}if(this.config.excludePaths?.some(u=>o.pathname.startsWith(u))||this.config.includePaths&&!this.config.includePaths.some(u=>o.pathname.startsWith(u)))return n;let i=t.headers.get("x-req-auth");if(!i)return{response:new Response(null,{status:401})};let c=i.indexOf(".");if(c<1)return{response:new Response(null,{status:401})};let a=i.slice(0,c),p=i.slice(c+1),d=R(a);if(!d)return{response:new Response(null,{status:401})};let l=r&&this.config.privateKey?await C(r,this.config.privateKey):void 0,f=await this.validateToken(d,a,p,l);return f.valid?{response:null,deviceId:f.deviceId}:{response:new Response(null,{status:401})}}getIp(t){return this.config.getClientIp?this.config.getClientIp(t):t.headers.get("CF-Connecting-IP")||t.headers.get("X-Forwarded-For")?.split(",")[0]?.trim()||t.headers.get("X-Real-IP")||"unknown"}async fetchBundle(){try{let t=await this.authedFetch("/b",{method:"GET"});return t.ok?await t.text():null}catch{return null}}async forwardToApi(t,s){return this.authedFetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:s.buffer})}async validateToken(t,s,r,n){try{let o={tokenHex:t,signature:r,payload:s};n&&(o.encryptedUser=n);let i=await this.authedFetch("/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)});if(!i.ok)return{valid:!1};let c=await i.json();return{valid:c.valid===!0,deviceId:c.deviceId}}catch{return{valid:!1}}}async authedFetch(t,s){let r=`${this.config.apiUrl}${t}`,n=Date.now().toString(),o=(s.method||"GET").toUpperCase(),i=`${n}.${o}.${t}`,c=await x(this.creds.secret,i),a=new Headers(s.headers);return a.set(y,this.creds.keyId),a.set(m,c),a.set(w,n),fetch(r,{...s,headers:a})}};async function P(e){let t=await crypto.subtle.importKey("raw",new TextEncoder().encode("obfious-script-v1"),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",t,new TextEncoder().encode(e));return`/${Array.from(new Uint8Array(s),n=>n.toString(16).padStart(2,"0")).join("").slice(0,10)}.js`}async function x(e,t){let s=new TextEncoder().encode(e),r=await crypto.subtle.importKey("raw",s,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),n=await crypto.subtle.sign("HMAC",r,new TextEncoder().encode(t));return Array.from(new Uint8Array(n),o=>o.toString(16).padStart(2,"0")).join("")}async function C(e,t){let s=new TextEncoder().encode(t),r=await crypto.subtle.importKey("raw",s,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),n=await crypto.subtle.sign("HMAC",r,new TextEncoder().encode(e));return Array.from(new Uint8Array(n),o=>o.toString(16).padStart(2,"0")).join("")}function R(e){try{let t=e.replace(/-/g,"+").replace(/_/g,"/");for(;t.length%4;)t+="=";let s=Uint8Array.from(atob(t),r=>r.charCodeAt(0));return s.length<9||s[0]!==33?null:Array.from(s.slice(1,9),r=>r.toString(16).padStart(2,"0")).join("")}catch{return null}}function S(e){let t=e.headers["x-forwarded-proto"]||e.headers["X-Forwarded-Proto"]||"https",s=e.headers.host||e.headers.Host||"localhost",r=`${t}://${s}${e.path}`;if(e.queryStringParameters){let c=new URLSearchParams;for(let[p,d]of Object.entries(e.queryStringParameters))d!=null&&c.set(p,d);let a=c.toString();a&&(r+=`?${a}`)}let n=new Headers;for(let[c,a]of Object.entries(e.headers))a&&n.set(c,a);let i=e.httpMethod!=="GET"&&e.httpMethod!=="HEAD"&&e.body!=null?e.isBase64Encoded?atob(e.body):e.body:null;return new Request(r,{method:e.httpMethod,headers:n,body:i})}async function A(e){let t={};return e.headers.forEach((s,r)=>{t[r]=s}),{statusCode:e.status,headers:t,body:await e.text()}}function H(e,t){let{creds:s,getUser:r,...n}=e,o=new g({...n,getClientIp:n.getClientIp??(i=>i.headers.get("x-lambda-source-ip")||i.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||"unknown"),getPlatformSignals:n.getPlatformSignals??(()=>({}))});return async(i,c)=>{let a=S(i),p=i.requestContext?.identity?.sourceIp||i.headers["x-forwarded-for"]?.split(",")[0]?.trim()||"unknown";a.headers.set("x-lambda-source-ip",p);let d=r?.(i),l=await o.protect(a,s,d);return l.response?A(l.response):(l.deviceId&&(i.headers["x-obfious-device-id"]=String(l.deviceId)),t(i,c))}}export{g as Obfious,H as obfiousHandler};
|
package/dist/nextjs.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
export interface
|
|
4
|
-
creds:
|
|
1
|
+
import { Obfious, ObfiousConfig, ObfiousCreds, ProtectResult } from "@obfious/js";
|
|
2
|
+
export { Obfious, ObfiousConfig, ObfiousCreds, ProtectResult };
|
|
3
|
+
export interface ObfiousMiddlewareConfig extends ObfiousConfig {
|
|
4
|
+
creds: ObfiousCreds;
|
|
5
5
|
}
|
|
6
|
-
export declare function createObfiousMiddleware(config:
|
|
7
|
-
export declare function obfiousScriptTag(obfious:
|
|
6
|
+
export declare function createObfiousMiddleware(config: ObfiousMiddlewareConfig): (request: Request) => Promise<Response | null>;
|
|
7
|
+
export declare function obfiousScriptTag(obfious: Obfious, nonce?: string): Promise<string>;
|
package/dist/nextjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var y="x-obfious-key",w="x-obfious-sig",m="x-obfious-ts",b=/\.(json|js|gif|png|woff2|css)$/,p=class{config;creds=null;scriptPathCache=null;constructor(t={}){this.config={...t,apiUrl:t.apiUrl??"https://api.obfious.com"}}async getScriptPath(){if(this.config.scriptPath)return this.config.scriptPath;if(this.scriptPathCache)return this.scriptPathCache;let t=this.config.stableString||"obfious-default";return this.scriptPathCache=await C(t),this.scriptPathCache}async scriptTag(t){let e=await this.getScriptPath(),n=t?.nonce?` nonce="${t.nonce}"`:"";return`<script src="${e}"${n} defer></script>`}async protect(t,e,n){let s={response:null};if(e&&!this.creds&&(this.creds=e),!this.creds)return s;let r=new URL(t.url);if(t.method==="GET"){let u=await this.getScriptPath();if(r.pathname===u){let l=await this.fetchBundle();if(l)return{response:new Response(l,{headers:{"Content-Type":"application/javascript","Cache-Control":"no-store"}})}}}if(t.method==="POST"&&b.test(r.pathname)){let u=t.clone(),l=new Uint8Array(await u.arrayBuffer());if(l.length>0&&l[0]===91)return{response:await this.forwardToApi(r.pathname,l)}}if(this.config.excludePaths?.some(u=>r.pathname.startsWith(u))||this.config.includePaths&&!this.config.includePaths.some(u=>r.pathname.startsWith(u)))return s;let o=t.headers.get("x-req-auth");if(!o)return{response:new Response(null,{status:401})};let a=o.indexOf(".");if(a<1)return{response:new Response(null,{status:401})};let c=o.slice(0,a),h=o.slice(a+1),d=v(c);if(!d)return{response:new Response(null,{status:401})};let g=n&&this.config.privateKey?await x(n,this.config.privateKey):void 0,f=await this.validateToken(d,c,h,g);return f.valid?{response:null,deviceId:f.deviceId}:{response:new Response(null,{status:401})}}getIp(t){return this.config.getClientIp?this.config.getClientIp(t):t.headers.get("CF-Connecting-IP")||t.headers.get("X-Forwarded-For")?.split(",")[0]?.trim()||t.headers.get("X-Real-IP")||"unknown"}async fetchBundle(){try{let t=await this.authedFetch("/b",{method:"GET"});return t.ok?await t.text():null}catch{return null}}async forwardToApi(t,e){return this.authedFetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:e.buffer})}async validateToken(t,e,n,s){try{let r={tokenHex:t,signature:n,payload:e};s&&(r.encryptedUser=s);let o=await this.authedFetch("/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok)return{valid:!1};let a=await o.json();return{valid:a.valid===!0,deviceId:a.deviceId}}catch{return{valid:!1}}}async authedFetch(t,e){let n=`${this.config.apiUrl}${t}`,s=Date.now().toString(),r=(e.method||"GET").toUpperCase(),o=`${s}.${r}.${t}`,a=await P(this.creds.secret,o),c=new Headers(e.headers);return c.set(y,this.creds.keyId),c.set(w,a),c.set(m,s),fetch(n,{...e,headers:c})}};async function C(i){let t=await crypto.subtle.importKey("raw",new TextEncoder().encode("obfious-script-v1"),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),e=await crypto.subtle.sign("HMAC",t,new TextEncoder().encode(i));return`/${Array.from(new Uint8Array(e),s=>s.toString(16).padStart(2,"0")).join("").slice(0,10)}.js`}async function P(i,t){let e=new TextEncoder().encode(i),n=await crypto.subtle.importKey("raw",e,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(t));return Array.from(new Uint8Array(s),r=>r.toString(16).padStart(2,"0")).join("")}async function x(i,t){let e=new TextEncoder().encode(t),n=await crypto.subtle.importKey("raw",e,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(i));return Array.from(new Uint8Array(s),r=>r.toString(16).padStart(2,"0")).join("")}function v(i){try{let t=i.replace(/-/g,"+").replace(/_/g,"/");for(;t.length%4;)t+="=";let e=Uint8Array.from(atob(t),n=>n.charCodeAt(0));return e.length<9||e[0]!==33?null:Array.from(e.slice(1,9),n=>n.toString(16).padStart(2,"0")).join("")}catch{return null}}function T(i){let{creds:t,...e}=i,n=new p({...e,getClientIp:e.getClientIp??(s=>s.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||s.headers.get("x-real-ip")||"unknown")});return async s=>(await n.protect(s,t)).response}async function A(i,t){return i.scriptTag({nonce:t})}export{p as
|
|
1
|
+
var y="x-obfious-key",w="x-obfious-sig",m="x-obfious-ts",b=/\.(json|js|gif|png|woff2|css)$/,p=class{config;creds=null;scriptPathCache=null;constructor(t={}){this.config={...t,apiUrl:t.apiUrl??"https://api.obfious.com"}}async getScriptPath(){if(this.config.scriptPath)return this.config.scriptPath;if(this.scriptPathCache)return this.scriptPathCache;let t=this.config.stableString||"obfious-default";return this.scriptPathCache=await C(t),this.scriptPathCache}async scriptTag(t){let e=await this.getScriptPath(),n=t?.nonce?` nonce="${t.nonce}"`:"";return`<script src="${e}"${n} defer></script>`}async protect(t,e,n){let s={response:null};if(e&&!this.creds&&(this.creds=e),!this.creds)return s;let r=new URL(t.url);if(t.method==="GET"){let u=await this.getScriptPath();if(r.pathname===u){let l=await this.fetchBundle();if(l)return{response:new Response(l,{headers:{"Content-Type":"application/javascript","Cache-Control":"no-store"}})}}}if(t.method==="POST"&&b.test(r.pathname)){let u=t.clone(),l=new Uint8Array(await u.arrayBuffer());if(l.length>0&&l[0]===91)return{response:await this.forwardToApi(r.pathname,l)}}if(this.config.excludePaths?.some(u=>r.pathname.startsWith(u))||this.config.includePaths&&!this.config.includePaths.some(u=>r.pathname.startsWith(u)))return s;let o=t.headers.get("x-req-auth");if(!o)return{response:new Response(null,{status:401})};let a=o.indexOf(".");if(a<1)return{response:new Response(null,{status:401})};let c=o.slice(0,a),h=o.slice(a+1),d=v(c);if(!d)return{response:new Response(null,{status:401})};let g=n&&this.config.privateKey?await x(n,this.config.privateKey):void 0,f=await this.validateToken(d,c,h,g);return f.valid?{response:null,deviceId:f.deviceId}:{response:new Response(null,{status:401})}}getIp(t){return this.config.getClientIp?this.config.getClientIp(t):t.headers.get("CF-Connecting-IP")||t.headers.get("X-Forwarded-For")?.split(",")[0]?.trim()||t.headers.get("X-Real-IP")||"unknown"}async fetchBundle(){try{let t=await this.authedFetch("/b",{method:"GET"});return t.ok?await t.text():null}catch{return null}}async forwardToApi(t,e){return this.authedFetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:e.buffer})}async validateToken(t,e,n,s){try{let r={tokenHex:t,signature:n,payload:e};s&&(r.encryptedUser=s);let o=await this.authedFetch("/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!o.ok)return{valid:!1};let a=await o.json();return{valid:a.valid===!0,deviceId:a.deviceId}}catch{return{valid:!1}}}async authedFetch(t,e){let n=`${this.config.apiUrl}${t}`,s=Date.now().toString(),r=(e.method||"GET").toUpperCase(),o=`${s}.${r}.${t}`,a=await P(this.creds.secret,o),c=new Headers(e.headers);return c.set(y,this.creds.keyId),c.set(w,a),c.set(m,s),fetch(n,{...e,headers:c})}};async function C(i){let t=await crypto.subtle.importKey("raw",new TextEncoder().encode("obfious-script-v1"),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),e=await crypto.subtle.sign("HMAC",t,new TextEncoder().encode(i));return`/${Array.from(new Uint8Array(e),s=>s.toString(16).padStart(2,"0")).join("").slice(0,10)}.js`}async function P(i,t){let e=new TextEncoder().encode(i),n=await crypto.subtle.importKey("raw",e,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(t));return Array.from(new Uint8Array(s),r=>r.toString(16).padStart(2,"0")).join("")}async function x(i,t){let e=new TextEncoder().encode(t),n=await crypto.subtle.importKey("raw",e,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(i));return Array.from(new Uint8Array(s),r=>r.toString(16).padStart(2,"0")).join("")}function v(i){try{let t=i.replace(/-/g,"+").replace(/_/g,"/");for(;t.length%4;)t+="=";let e=Uint8Array.from(atob(t),n=>n.charCodeAt(0));return e.length<9||e[0]!==33?null:Array.from(e.slice(1,9),n=>n.toString(16).padStart(2,"0")).join("")}catch{return null}}function T(i){let{creds:t,...e}=i,n=new p({...e,getClientIp:e.getClientIp??(s=>s.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||s.headers.get("x-real-ip")||"unknown")});return async s=>(await n.protect(s,t)).response}async function A(i,t){return i.scriptTag({nonce:t})}export{p as Obfious,T as createObfiousMiddleware,A as obfiousScriptTag};
|