securequ 1.1.3 → 1.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/client/Base.d.ts +1 -0
- package/client/Base.js +1 -1
- package/client/Base.js.map +1 -1
- package/client/Base.mjs +1 -1
- package/client/Base.mjs.map +1 -1
- package/client/index.d.ts +2 -1
- package/client/index.js +1 -1
- package/client/index.js.map +1 -1
- package/client/index.mjs +1 -1
- package/client/index.mjs.map +1 -1
- package/client/types.d.ts +5 -5
- package/include/File.js +1 -1
- package/include/File.js.map +1 -1
- package/include/File.mjs +1 -1
- package/include/File.mjs.map +1 -1
- package/index.d.ts +1 -1
- package/package.json +1 -1
- package/readme.md +7 -9
- package/server/Base.d.ts +4 -3
- package/server/Base.js +1 -1
- package/server/Base.js.map +1 -1
- package/server/Base.mjs +1 -1
- package/server/Base.mjs.map +1 -1
- package/server/index.d.ts +4 -3
- package/server/index.js +1 -1
- package/server/index.js.map +1 -1
- package/server/index.mjs +1 -1
- package/server/index.mjs.map +1 -1
- package/server/types.d.ts +18 -17
package/client/Base.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ declare class Base {
|
|
|
5
5
|
protected loadingHandshake: boolean;
|
|
6
6
|
protected secret_length: number;
|
|
7
7
|
protected handshakeInfo: HandshakeInfo | null;
|
|
8
|
+
readonly CONTENT_TYPE = "application/octet-stream";
|
|
8
9
|
constructor(config: SecurequClientConfig);
|
|
9
10
|
protected hooksCall(hook: keyof NonNullable<SecurequClientConfig['hooks']>, ...args: any[]): any;
|
|
10
11
|
protected getSecret(): Promise<{
|
package/client/Base.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("../include/crypto.js"),e=require("xanfetch");const s=new Map;exports.default=class{constructor(t){this.loadingHandshake=!1,this.secret_length=0,this.handshakeInfo=null,this.config=Object.assign({},t);const e=new URL(t.url);if(e.search||e.hash)throw new Error(`Invalid config url ${t.url}. Search params or Hash url is not supported in config.url`);if(t.url=`${e.origin}${e.pathname}`,s.has(t.url))throw new Error("Client is Blocked!")}hooksCall(t,...e){if(this.config.hooks&&this.config.hooks[t])return this.config.hooks[t](...e)}async getSecret(){let e=this.config.secret,s=e.substring(0,this.secret_length);return{full:e,secret:s,hash:(await t.default.hash(s)).substring(0,this.secret_length)}}async url(t){const e=await this.getSecret(),s=this.config.url;return"/"===t&&(t=""),(t=(t=(t=t.trim()).startsWith("/")?t.substring(1):t).endsWith("/")?t.substring(0,t.length-1):t)&&(t=`/${t}`),new URL(`${s}/${e.hash}${t}`)}async getHeaders(e,s){var a,n,i;const r=await this.url(e),h=await this.getSecret();let o={};return this.handshakeInfo&&(o["X-SIGNETURE"]=await t.default.encrypt({signeture:null===(a=this.handshakeInfo)||void 0===a?void 0:a.signeture,expire:Date.now()+this.handshakeInfo.timeDiffarenc+1e4},h.secret)||""),Object.assign(Object.assign(Object.assign(Object.assign({},null===(i=null===(n=this.config)||void 0===n?void 0:n.defaultOptions)||void 0===i?void 0:i.headers),null==s?void 0:s.headers),o),{"Content-Type":"
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("../include/crypto.js"),e=require("xanfetch");const s=new Map;exports.default=class{constructor(t){this.loadingHandshake=!1,this.secret_length=0,this.handshakeInfo=null,this.CONTENT_TYPE="application/octet-stream",this.config=Object.assign({},t);const e=new URL(t.url);if(e.search||e.hash)throw new Error(`Invalid config url ${t.url}. Search params or Hash url is not supported in config.url`);if(t.url=`${e.origin}${e.pathname}`,s.has(t.url))throw new Error("Client is Blocked!")}hooksCall(t,...e){if(this.config.hooks&&this.config.hooks[t])return this.config.hooks[t](...e)}async getSecret(){let e=this.config.secret,s=e.substring(0,this.secret_length);return{full:e,secret:s,hash:(await t.default.hash(s)).substring(0,this.secret_length)}}async url(t){const e=await this.getSecret(),s=this.config.url;return"/"===t&&(t=""),(t=(t=(t=t.trim()).startsWith("/")?t.substring(1):t).endsWith("/")?t.substring(0,t.length-1):t)&&(t=`/${t}`),new URL(`${s}/${e.hash}${t}`)}async getHeaders(e,s){var a,n,i;const r=await this.url(e),h=await this.getSecret();let o={};return this.handshakeInfo&&(o["X-SIGNETURE"]=await t.default.encrypt({signeture:null===(a=this.handshakeInfo)||void 0===a?void 0:a.signeture,expire:Date.now()+this.handshakeInfo.timeDiffarenc+1e4},h.secret)||""),o=Object.assign(Object.assign(Object.assign(Object.assign({},null===(i=null===(n=this.config)||void 0===n?void 0:n.defaultOptions)||void 0===i?void 0:i.headers),null==s?void 0:s.headers),o),{"Content-Type":this.CONTENT_TYPE,"X-ORIGIN":r.origin,"X-METHOD":((null==s?void 0:s.method)||"GET").toUpperCase()}),o}async awaitForHandshake(){this.loadingHandshake&&await new Promise(t=>{const e=setInterval(()=>{this.loadingHandshake||(clearInterval(e),t(null))},100)}),this.handshakeInfo||await this.handshake()}async handshake(){await this.hooksCall("beforeHandshake"),this.handshakeInfo=null,this.loadingHandshake=!0;let t=this.config.secret.length,e=3*Math.floor(t/4);this.secret_length=Math.floor(Math.random()*(t-e+1))+e;const s=await this.getSecret(),a=await this.fetch("/",{method:"POST",body:{hash:s.hash,clientTime:(new Date).toISOString(),secret:s.secret}});this.handshakeInfo=a.data,this.loadingHandshake=!1,await this.hooksCall("afterHandshake",this.handshakeInfo)}async fetch(s,a){var n,i;const r="/"!==s&&(null===(n=this.handshakeInfo)||void 0===n?void 0:n.dev),h=await this.getSecret(),o=await this.url(s);let c=Object.fromEntries(o.searchParams.entries());const l=Object.assign({},a);let d=Object.assign({},c);if(Object.keys(c).length>0)for(let t in c)o.searchParams.delete(t);if(null==l?void 0:l.params){for(let t in l.params)d[t]=l.params[t];delete l.params}if(Object.keys(d).length>0)if(r)l.params=d;else{const e=await t.default.encrypt(d,h.secret);o.href=o.href+"?"+encodeURIComponent(e)}const u=Object.assign(Object.assign(Object.assign({method:"GET"},null===(i=this.config)||void 0===i?void 0:i.defaultOptions),l),{headers:await this.getHeaders(s,l)});(null==u?void 0:u.body)&&(u.body=r?JSON.stringify(u.body):await t.default.encryptBuffer(u.body,h.secret));const f=await e(o.href,u);if(r){const t=await f.text(),e=JSON.parse(t);return{success:f.ok,message:f.ok?f.statusText:e,data:f.ok?e:null,code:f.status}}const g=await f.arrayBuffer(),k=await t.default.decryptBuffer(new Uint8Array(g),h.secret);return{success:f.ok,message:f.ok?f.statusText:k||f.statusText,data:f.ok?k:null,code:f.status}}};//# sourceMappingURL=Base.js.map
|
package/client/Base.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Base.js","sources":["../../src/client/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\r\nimport { HandshakeInfo, HttpRequestInit, SecurequClientConfig, SecurequClientResponse } from \"./types\";\r\nimport xanFetch from 'xanfetch'\r\n\r\n\r\nconst Clients = new Map<string, Base>()\r\n\r\nclass Base {\r\n protected config: SecurequClientConfig;\r\n protected loadingHandshake: boolean = false;\r\n protected secret_length: number = 0;\r\n protected handshakeInfo: HandshakeInfo | null = null;\r\n\r\n constructor(config: SecurequClientConfig) {\r\n this.config = { ...config }\r\n const url = new URL(config.url)\r\n if (url.search || url.hash) throw new Error(`Invalid config url ${config.url}. Search params or Hash url is not supported in config.url`)\r\n config.url = `${url.origin}${url.pathname}`\r\n\r\n if (Clients.has(config.url)) {\r\n throw new Error(`Client is Blocked!`);\r\n }\r\n }\r\n\r\n protected hooksCall(hook: keyof NonNullable<SecurequClientConfig['hooks']>, ...args: any[]) {\r\n if (this.config.hooks && this.config.hooks[hook]) {\r\n return (this.config.hooks[hook] as Function)(...args)\r\n }\r\n }\r\n\r\n protected async getSecret() {\r\n let full = this.config.secret\r\n let secret = full.substring(0, this.secret_length)\r\n let hash = (await crypto.hash(secret)).substring(0, this.secret_length)\r\n return { full, secret, hash }\r\n }\r\n\r\n protected async url(path: string) {\r\n const secret = await this.getSecret()\r\n const base = this.config.url;\r\n if (path === '/') path = ''\r\n path = path.trim();\r\n path = path.startsWith('/') ? path.substring(1) : path\r\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\r\n if (path) path = `/${path}`\r\n return new URL(`${base}/${secret.hash}${path}`);\r\n }\r\n\r\n protected async getHeaders(path: string, init?: HttpRequestInit) {\r\n const url = await this.url(path)\r\n const secret = await this.getSecret()\r\n let headers: any = {};\r\n if (this.handshakeInfo) {\r\n headers[\"X-SIGNETURE\"] = await crypto.encrypt({\r\n signeture: this.handshakeInfo?.signeture,\r\n expire: Date.now() + this.handshakeInfo!.timeDiffarenc + 10000 // 10 seconds\r\n }, secret.secret) || '';\r\n }\r\n return {\r\n ...this.config?.defaultOptions?.headers,\r\n ...init?.headers,\r\n ...headers,\r\n 'Content-Type': 'application/octet-stream',\r\n \"X-ORIGIN\": url.origin\r\n }\r\n }\r\n\r\n protected async awaitForHandshake() {\r\n if (this.loadingHandshake) {\r\n await new Promise((resolve) => {\r\n const interval = setInterval(() => {\r\n if (!this.loadingHandshake) {\r\n clearInterval(interval);\r\n resolve(null);\r\n }\r\n }, 100);\r\n })\r\n }\r\n if (!this.handshakeInfo) {\r\n await this.handshake();\r\n }\r\n }\r\n\r\n async handshake() {\r\n await this.hooksCall('beforeHandshake');\r\n this.handshakeInfo = null;\r\n this.loadingHandshake = true;\r\n\r\n let max = this.config.secret.length\r\n let min = Math.floor(max / 4) * 3\r\n this.secret_length = Math.floor(Math.random() * (max - min + 1)) + min\r\n\r\n const secret = await this.getSecret()\r\n const res = await this.fetch('/', {\r\n method: 'POST',\r\n body: {\r\n hash: secret.hash,\r\n clientTime: new Date().toISOString(),\r\n secret: secret.secret,\r\n }\r\n })\r\n this.handshakeInfo = res.data\r\n this.loadingHandshake = false;\r\n await this.hooksCall('afterHandshake', this.handshakeInfo);\r\n }\r\n\r\n protected async fetch(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\r\n const isDev = path !== '/' && this.handshakeInfo?.dev\r\n const secret = await this.getSecret()\r\n const url = await this.url(path)\r\n let sparams = Object.fromEntries(url.searchParams.entries())\r\n const _init = { ...init }\r\n let params: any = {\r\n ...sparams,\r\n }\r\n\r\n if (Object.keys(sparams).length > 0) {\r\n for (let key in sparams) {\r\n url.searchParams.delete(key)\r\n }\r\n }\r\n\r\n if (_init?.params) {\r\n for (let key in _init.params) {\r\n params[key] = _init.params[key]\r\n }\r\n delete _init.params\r\n }\r\n\r\n if (Object.keys(params).length > 0) {\r\n if (isDev) {\r\n _init.params = params\r\n } else {\r\n const enc = await crypto.encrypt(params, secret.secret)\r\n url.href = url.href + \"?\" + encodeURIComponent(enc)\r\n }\r\n }\r\n\r\n const httpOption: any = {\r\n method: \"GET\",\r\n ...this.config?.defaultOptions,\r\n ..._init,\r\n headers: await this.getHeaders(path, init)\r\n }\r\n\r\n if (httpOption?.body) {\r\n if (isDev) {\r\n httpOption.body = JSON.stringify(httpOption.body)\r\n } else {\r\n httpOption.body = await crypto.encryptBuffer(httpOption.body, secret.secret);\r\n }\r\n }\r\n const res = await xanFetch(url.href, httpOption)\r\n if (isDev) {\r\n const value = await res.text()\r\n const val = JSON.parse(value)\r\n return {\r\n success: res.ok,\r\n message: res.ok ? res.statusText : val,\r\n data: res.ok ? val : null,\r\n code: res.status\r\n }\r\n }\r\n const value = await res.arrayBuffer()\r\n const val = await crypto.decryptBuffer(new Uint8Array(value), secret.secret) as any\r\n return {\r\n success: res.ok,\r\n message: res.ok ? res.statusText : val,\r\n data: res.ok ? val : null,\r\n code: res.status\r\n }\r\n }\r\n\r\n}\r\n\r\nexport default Base;\r\n"],"names":["Object","defineProperty","exports","value","crypto","require","xanFetch","Clients","Map","default","constructor","config","this","loadingHandshake","secret_length","handshakeInfo","assign","url","URL","search","hash","Error","origin","pathname","has","hooksCall","hook","args","hooks","getSecret","full","secret","substring","path","base","trim","startsWith","endsWith","length","getHeaders","init","headers","encrypt","signeture","_a","expire","Date","now","timeDiffarenc","_c","_b","defaultOptions","awaitForHandshake","Promise","resolve","interval","setInterval","clearInterval","handshake","max","min","Math","floor","random","res","fetch","method","body","clientTime","toISOString","data","isDev","dev","sparams","fromEntries","searchParams","entries","_init","params","keys","key","delete","enc","href","encodeURIComponent","httpOption","JSON","stringify","encryptBuffer","text","val","parse","success","ok","message","statusText","code","status","arrayBuffer","decryptBuffer","Uint8Array"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Base.js","sources":["../../src/client/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\r\nimport { HandshakeInfo, HttpRequestInit, SecurequClientConfig, SecurequClientResponse } from \"./types\";\r\nimport xanFetch from 'xanfetch'\r\n\r\n\r\nconst Clients = new Map<string, Base>()\r\n\r\nclass Base {\r\n protected config: SecurequClientConfig;\r\n protected loadingHandshake: boolean = false;\r\n protected secret_length: number = 0;\r\n protected handshakeInfo: HandshakeInfo | null = null;\r\n readonly CONTENT_TYPE = \"application/octet-stream\";\r\n\r\n constructor(config: SecurequClientConfig) {\r\n this.config = {\r\n ...config,\r\n }\r\n const url = new URL(config.url)\r\n if (url.search || url.hash) throw new Error(`Invalid config url ${config.url}. Search params or Hash url is not supported in config.url`)\r\n config.url = `${url.origin}${url.pathname}`\r\n\r\n if (Clients.has(config.url)) {\r\n throw new Error(`Client is Blocked!`);\r\n }\r\n }\r\n\r\n protected hooksCall(hook: keyof NonNullable<SecurequClientConfig['hooks']>, ...args: any[]) {\r\n if (this.config.hooks && this.config.hooks[hook]) {\r\n return (this.config.hooks[hook] as Function)(...args)\r\n }\r\n }\r\n\r\n protected async getSecret() {\r\n let full = this.config.secret\r\n let secret = full.substring(0, this.secret_length)\r\n let hash = (await crypto.hash(secret)).substring(0, this.secret_length)\r\n return { full, secret, hash }\r\n }\r\n\r\n protected async url(path: string) {\r\n const secret = await this.getSecret()\r\n const base = this.config.url;\r\n if (path === '/') path = ''\r\n path = path.trim();\r\n path = path.startsWith('/') ? path.substring(1) : path\r\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\r\n if (path) path = `/${path}`\r\n return new URL(`${base}/${secret.hash}${path}`);\r\n }\r\n\r\n protected async getHeaders(path: string, init?: HttpRequestInit) {\r\n const url = await this.url(path)\r\n const secret = await this.getSecret()\r\n let headers: any = {};\r\n if (this.handshakeInfo) {\r\n headers[\"X-SIGNETURE\"] = await crypto.encrypt({\r\n signeture: this.handshakeInfo?.signeture,\r\n expire: Date.now() + this.handshakeInfo!.timeDiffarenc + 10000 // 10 seconds\r\n }, secret.secret) || '';\r\n }\r\n\r\n headers = {\r\n ...this.config?.defaultOptions?.headers,\r\n ...init?.headers,\r\n ...headers,\r\n 'Content-Type': this.CONTENT_TYPE,\r\n \"X-ORIGIN\": url.origin,\r\n \"X-METHOD\": (init?.method || 'GET').toUpperCase()\r\n }\r\n\r\n return headers;\r\n }\r\n\r\n protected async awaitForHandshake() {\r\n if (this.loadingHandshake) {\r\n await new Promise((resolve) => {\r\n const interval = setInterval(() => {\r\n if (!this.loadingHandshake) {\r\n clearInterval(interval);\r\n resolve(null);\r\n }\r\n }, 100);\r\n })\r\n }\r\n if (!this.handshakeInfo) {\r\n await this.handshake();\r\n }\r\n }\r\n\r\n async handshake() {\r\n await this.hooksCall('beforeHandshake');\r\n this.handshakeInfo = null;\r\n this.loadingHandshake = true;\r\n\r\n let max = this.config.secret.length\r\n let min = Math.floor(max / 4) * 3\r\n this.secret_length = Math.floor(Math.random() * (max - min + 1)) + min\r\n\r\n const secret = await this.getSecret()\r\n const res = await this.fetch('/', {\r\n method: 'POST',\r\n body: {\r\n hash: secret.hash,\r\n clientTime: new Date().toISOString(),\r\n secret: secret.secret,\r\n }\r\n })\r\n this.handshakeInfo = res.data\r\n this.loadingHandshake = false;\r\n await this.hooksCall('afterHandshake', this.handshakeInfo);\r\n }\r\n\r\n protected async fetch(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\r\n const isDev = path !== '/' && this.handshakeInfo?.dev\r\n const secret = await this.getSecret()\r\n const url = await this.url(path)\r\n let sparams = Object.fromEntries(url.searchParams.entries())\r\n const _init = { ...init }\r\n let params: any = {\r\n ...sparams,\r\n }\r\n\r\n if (Object.keys(sparams).length > 0) {\r\n for (let key in sparams) {\r\n url.searchParams.delete(key)\r\n }\r\n }\r\n\r\n if (_init?.params) {\r\n for (let key in _init.params) {\r\n params[key] = _init.params[key]\r\n }\r\n delete _init.params\r\n }\r\n\r\n if (Object.keys(params).length > 0) {\r\n if (isDev) {\r\n _init.params = params\r\n } else {\r\n const enc = await crypto.encrypt(params, secret.secret)\r\n url.href = url.href + \"?\" + encodeURIComponent(enc)\r\n }\r\n }\r\n\r\n const httpOption: any = {\r\n method: \"GET\",\r\n ...this.config?.defaultOptions,\r\n ..._init,\r\n headers: await this.getHeaders(path, _init)\r\n }\r\n\r\n if (httpOption?.body) {\r\n if (isDev) {\r\n httpOption.body = JSON.stringify(httpOption.body)\r\n } else {\r\n httpOption.body = await crypto.encryptBuffer(httpOption.body, secret.secret);\r\n }\r\n }\r\n const res = await xanFetch(url.href, httpOption)\r\n if (isDev) {\r\n const value = await res.text()\r\n const val = JSON.parse(value)\r\n return {\r\n success: res.ok,\r\n message: res.ok ? res.statusText : val,\r\n data: res.ok ? val : null,\r\n code: res.status\r\n }\r\n }\r\n const value = await res.arrayBuffer()\r\n const val = await crypto.decryptBuffer(new Uint8Array(value), secret.secret) as any\r\n\r\n return {\r\n success: res.ok,\r\n message: res.ok ? res.statusText : (val || res.statusText),\r\n data: res.ok ? val : null,\r\n code: res.status\r\n }\r\n }\r\n\r\n}\r\n\r\nexport default Base;\r\n"],"names":["Object","defineProperty","exports","value","crypto","require","xanFetch","Clients","Map","default","constructor","config","this","loadingHandshake","secret_length","handshakeInfo","CONTENT_TYPE","assign","url","URL","search","hash","Error","origin","pathname","has","hooksCall","hook","args","hooks","getSecret","full","secret","substring","path","base","trim","startsWith","endsWith","length","getHeaders","init","headers","encrypt","signeture","_a","expire","Date","now","timeDiffarenc","_b","defaultOptions","_c","method","toUpperCase","awaitForHandshake","Promise","resolve","interval","setInterval","clearInterval","handshake","max","min","Math","floor","random","res","fetch","body","clientTime","toISOString","data","isDev","dev","sparams","fromEntries","searchParams","entries","_init","params","keys","key","delete","enc","href","encodeURIComponent","httpOption","JSON","stringify","encryptBuffer","text","val","parse","success","ok","message","statusText","code","status","arrayBuffer","decryptBuffer","Uint8Array"],"mappings":"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"}
|
package/client/Base.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import t from"../include/crypto.mjs";import e from"xanfetch";const s=new Map;class a{constructor(t){this.loadingHandshake=!1,this.secret_length=0,this.handshakeInfo=null,this.config=Object.assign({},t);const e=new URL(t.url);if(e.search||e.hash)throw new Error(`Invalid config url ${t.url}. Search params or Hash url is not supported in config.url`);if(t.url=`${e.origin}${e.pathname}`,s.has(t.url))throw new Error("Client is Blocked!")}hooksCall(t,...e){if(this.config.hooks&&this.config.hooks[t])return this.config.hooks[t](...e)}async getSecret(){let e=this.config.secret,s=e.substring(0,this.secret_length);return{full:e,secret:s,hash:(await t.hash(s)).substring(0,this.secret_length)}}async url(t){const e=await this.getSecret(),s=this.config.url;return"/"===t&&(t=""),(t=(t=(t=t.trim()).startsWith("/")?t.substring(1):t).endsWith("/")?t.substring(0,t.length-1):t)&&(t=`/${t}`),new URL(`${s}/${e.hash}${t}`)}async getHeaders(e,s){var a,n,i;const r=await this.url(e),h=await this.getSecret();let o={};return this.handshakeInfo&&(o["X-SIGNETURE"]=await t.encrypt({signeture:null===(a=this.handshakeInfo)||void 0===a?void 0:a.signeture,expire:Date.now()+this.handshakeInfo.timeDiffarenc+1e4},h.secret)||""),Object.assign(Object.assign(Object.assign(Object.assign({},null===(i=null===(n=this.config)||void 0===n?void 0:n.defaultOptions)||void 0===i?void 0:i.headers),null==s?void 0:s.headers),o),{"Content-Type":"
|
|
1
|
+
import t from"../include/crypto.mjs";import e from"xanfetch";const s=new Map;class a{constructor(t){this.loadingHandshake=!1,this.secret_length=0,this.handshakeInfo=null,this.CONTENT_TYPE="application/octet-stream",this.config=Object.assign({},t);const e=new URL(t.url);if(e.search||e.hash)throw new Error(`Invalid config url ${t.url}. Search params or Hash url is not supported in config.url`);if(t.url=`${e.origin}${e.pathname}`,s.has(t.url))throw new Error("Client is Blocked!")}hooksCall(t,...e){if(this.config.hooks&&this.config.hooks[t])return this.config.hooks[t](...e)}async getSecret(){let e=this.config.secret,s=e.substring(0,this.secret_length);return{full:e,secret:s,hash:(await t.hash(s)).substring(0,this.secret_length)}}async url(t){const e=await this.getSecret(),s=this.config.url;return"/"===t&&(t=""),(t=(t=(t=t.trim()).startsWith("/")?t.substring(1):t).endsWith("/")?t.substring(0,t.length-1):t)&&(t=`/${t}`),new URL(`${s}/${e.hash}${t}`)}async getHeaders(e,s){var a,n,i;const r=await this.url(e),h=await this.getSecret();let o={};return this.handshakeInfo&&(o["X-SIGNETURE"]=await t.encrypt({signeture:null===(a=this.handshakeInfo)||void 0===a?void 0:a.signeture,expire:Date.now()+this.handshakeInfo.timeDiffarenc+1e4},h.secret)||""),o=Object.assign(Object.assign(Object.assign(Object.assign({},null===(i=null===(n=this.config)||void 0===n?void 0:n.defaultOptions)||void 0===i?void 0:i.headers),null==s?void 0:s.headers),o),{"Content-Type":this.CONTENT_TYPE,"X-ORIGIN":r.origin,"X-METHOD":((null==s?void 0:s.method)||"GET").toUpperCase()}),o}async awaitForHandshake(){this.loadingHandshake&&await new Promise(t=>{const e=setInterval(()=>{this.loadingHandshake||(clearInterval(e),t(null))},100)}),this.handshakeInfo||await this.handshake()}async handshake(){await this.hooksCall("beforeHandshake"),this.handshakeInfo=null,this.loadingHandshake=!0;let t=this.config.secret.length,e=3*Math.floor(t/4);this.secret_length=Math.floor(Math.random()*(t-e+1))+e;const s=await this.getSecret(),a=await this.fetch("/",{method:"POST",body:{hash:s.hash,clientTime:(new Date).toISOString(),secret:s.secret}});this.handshakeInfo=a.data,this.loadingHandshake=!1,await this.hooksCall("afterHandshake",this.handshakeInfo)}async fetch(s,a){var n,i;const r="/"!==s&&(null===(n=this.handshakeInfo)||void 0===n?void 0:n.dev),h=await this.getSecret(),o=await this.url(s);let c=Object.fromEntries(o.searchParams.entries());const l=Object.assign({},a);let d=Object.assign({},c);if(Object.keys(c).length>0)for(let t in c)o.searchParams.delete(t);if(null==l?void 0:l.params){for(let t in l.params)d[t]=l.params[t];delete l.params}if(Object.keys(d).length>0)if(r)l.params=d;else{const e=await t.encrypt(d,h.secret);o.href=o.href+"?"+encodeURIComponent(e)}const f=Object.assign(Object.assign(Object.assign({method:"GET"},null===(i=this.config)||void 0===i?void 0:i.defaultOptions),l),{headers:await this.getHeaders(s,l)});(null==f?void 0:f.body)&&(f.body=r?JSON.stringify(f.body):await t.encryptBuffer(f.body,h.secret));const u=await e(o.href,f);if(r){const t=await u.text(),e=JSON.parse(t);return{success:u.ok,message:u.ok?u.statusText:e,data:u.ok?e:null,code:u.status}}const g=await u.arrayBuffer(),k=await t.decryptBuffer(new Uint8Array(g),h.secret);return{success:u.ok,message:u.ok?u.statusText:k||u.statusText,data:u.ok?k:null,code:u.status}}}export{a as default};//# sourceMappingURL=Base.mjs.map
|
package/client/Base.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Base.mjs","sources":["../../src/client/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\r\nimport { HandshakeInfo, HttpRequestInit, SecurequClientConfig, SecurequClientResponse } from \"./types\";\r\nimport xanFetch from 'xanfetch'\r\n\r\n\r\nconst Clients = new Map<string, Base>()\r\n\r\nclass Base {\r\n protected config: SecurequClientConfig;\r\n protected loadingHandshake: boolean = false;\r\n protected secret_length: number = 0;\r\n protected handshakeInfo: HandshakeInfo | null = null;\r\n\r\n constructor(config: SecurequClientConfig) {\r\n this.config = { ...config }\r\n const url = new URL(config.url)\r\n if (url.search || url.hash) throw new Error(`Invalid config url ${config.url}. Search params or Hash url is not supported in config.url`)\r\n config.url = `${url.origin}${url.pathname}`\r\n\r\n if (Clients.has(config.url)) {\r\n throw new Error(`Client is Blocked!`);\r\n }\r\n }\r\n\r\n protected hooksCall(hook: keyof NonNullable<SecurequClientConfig['hooks']>, ...args: any[]) {\r\n if (this.config.hooks && this.config.hooks[hook]) {\r\n return (this.config.hooks[hook] as Function)(...args)\r\n }\r\n }\r\n\r\n protected async getSecret() {\r\n let full = this.config.secret\r\n let secret = full.substring(0, this.secret_length)\r\n let hash = (await crypto.hash(secret)).substring(0, this.secret_length)\r\n return { full, secret, hash }\r\n }\r\n\r\n protected async url(path: string) {\r\n const secret = await this.getSecret()\r\n const base = this.config.url;\r\n if (path === '/') path = ''\r\n path = path.trim();\r\n path = path.startsWith('/') ? path.substring(1) : path\r\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\r\n if (path) path = `/${path}`\r\n return new URL(`${base}/${secret.hash}${path}`);\r\n }\r\n\r\n protected async getHeaders(path: string, init?: HttpRequestInit) {\r\n const url = await this.url(path)\r\n const secret = await this.getSecret()\r\n let headers: any = {};\r\n if (this.handshakeInfo) {\r\n headers[\"X-SIGNETURE\"] = await crypto.encrypt({\r\n signeture: this.handshakeInfo?.signeture,\r\n expire: Date.now() + this.handshakeInfo!.timeDiffarenc + 10000 // 10 seconds\r\n }, secret.secret) || '';\r\n }\r\n return {\r\n ...this.config?.defaultOptions?.headers,\r\n ...init?.headers,\r\n ...headers,\r\n 'Content-Type': 'application/octet-stream',\r\n \"X-ORIGIN\": url.origin\r\n }\r\n }\r\n\r\n protected async awaitForHandshake() {\r\n if (this.loadingHandshake) {\r\n await new Promise((resolve) => {\r\n const interval = setInterval(() => {\r\n if (!this.loadingHandshake) {\r\n clearInterval(interval);\r\n resolve(null);\r\n }\r\n }, 100);\r\n })\r\n }\r\n if (!this.handshakeInfo) {\r\n await this.handshake();\r\n }\r\n }\r\n\r\n async handshake() {\r\n await this.hooksCall('beforeHandshake');\r\n this.handshakeInfo = null;\r\n this.loadingHandshake = true;\r\n\r\n let max = this.config.secret.length\r\n let min = Math.floor(max / 4) * 3\r\n this.secret_length = Math.floor(Math.random() * (max - min + 1)) + min\r\n\r\n const secret = await this.getSecret()\r\n const res = await this.fetch('/', {\r\n method: 'POST',\r\n body: {\r\n hash: secret.hash,\r\n clientTime: new Date().toISOString(),\r\n secret: secret.secret,\r\n }\r\n })\r\n this.handshakeInfo = res.data\r\n this.loadingHandshake = false;\r\n await this.hooksCall('afterHandshake', this.handshakeInfo);\r\n }\r\n\r\n protected async fetch(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\r\n const isDev = path !== '/' && this.handshakeInfo?.dev\r\n const secret = await this.getSecret()\r\n const url = await this.url(path)\r\n let sparams = Object.fromEntries(url.searchParams.entries())\r\n const _init = { ...init }\r\n let params: any = {\r\n ...sparams,\r\n }\r\n\r\n if (Object.keys(sparams).length > 0) {\r\n for (let key in sparams) {\r\n url.searchParams.delete(key)\r\n }\r\n }\r\n\r\n if (_init?.params) {\r\n for (let key in _init.params) {\r\n params[key] = _init.params[key]\r\n }\r\n delete _init.params\r\n }\r\n\r\n if (Object.keys(params).length > 0) {\r\n if (isDev) {\r\n _init.params = params\r\n } else {\r\n const enc = await crypto.encrypt(params, secret.secret)\r\n url.href = url.href + \"?\" + encodeURIComponent(enc)\r\n }\r\n }\r\n\r\n const httpOption: any = {\r\n method: \"GET\",\r\n ...this.config?.defaultOptions,\r\n ..._init,\r\n headers: await this.getHeaders(path, init)\r\n }\r\n\r\n if (httpOption?.body) {\r\n if (isDev) {\r\n httpOption.body = JSON.stringify(httpOption.body)\r\n } else {\r\n httpOption.body = await crypto.encryptBuffer(httpOption.body, secret.secret);\r\n }\r\n }\r\n const res = await xanFetch(url.href, httpOption)\r\n if (isDev) {\r\n const value = await res.text()\r\n const val = JSON.parse(value)\r\n return {\r\n success: res.ok,\r\n message: res.ok ? res.statusText : val,\r\n data: res.ok ? val : null,\r\n code: res.status\r\n }\r\n }\r\n const value = await res.arrayBuffer()\r\n const val = await crypto.decryptBuffer(new Uint8Array(value), secret.secret) as any\r\n return {\r\n success: res.ok,\r\n message: res.ok ? res.statusText : val,\r\n data: res.ok ? val : null,\r\n code: res.status\r\n }\r\n }\r\n\r\n}\r\n\r\nexport default Base;\r\n"],"names":["crypto","xanFetch","Clients","Map","Base","constructor","config","this","loadingHandshake","secret_length","handshakeInfo","Object","assign","url","URL","search","hash","Error","origin","pathname","has","hooksCall","hook","args","hooks","getSecret","full","secret","substring","path","base","trim","startsWith","endsWith","length","getHeaders","init","headers","encrypt","signeture","_a","expire","Date","now","timeDiffarenc","_c","_b","defaultOptions","awaitForHandshake","Promise","resolve","interval","setInterval","clearInterval","handshake","max","min","Math","floor","random","res","fetch","method","body","clientTime","toISOString","data","isDev","dev","sparams","fromEntries","searchParams","entries","_init","params","keys","key","delete","enc","href","encodeURIComponent","httpOption","JSON","stringify","encryptBuffer","value","text","val","parse","success","ok","message","statusText","code","status","arrayBuffer","decryptBuffer","Uint8Array"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Base.mjs","sources":["../../src/client/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\r\nimport { HandshakeInfo, HttpRequestInit, SecurequClientConfig, SecurequClientResponse } from \"./types\";\r\nimport xanFetch from 'xanfetch'\r\n\r\n\r\nconst Clients = new Map<string, Base>()\r\n\r\nclass Base {\r\n protected config: SecurequClientConfig;\r\n protected loadingHandshake: boolean = false;\r\n protected secret_length: number = 0;\r\n protected handshakeInfo: HandshakeInfo | null = null;\r\n readonly CONTENT_TYPE = \"application/octet-stream\";\r\n\r\n constructor(config: SecurequClientConfig) {\r\n this.config = {\r\n ...config,\r\n }\r\n const url = new URL(config.url)\r\n if (url.search || url.hash) throw new Error(`Invalid config url ${config.url}. Search params or Hash url is not supported in config.url`)\r\n config.url = `${url.origin}${url.pathname}`\r\n\r\n if (Clients.has(config.url)) {\r\n throw new Error(`Client is Blocked!`);\r\n }\r\n }\r\n\r\n protected hooksCall(hook: keyof NonNullable<SecurequClientConfig['hooks']>, ...args: any[]) {\r\n if (this.config.hooks && this.config.hooks[hook]) {\r\n return (this.config.hooks[hook] as Function)(...args)\r\n }\r\n }\r\n\r\n protected async getSecret() {\r\n let full = this.config.secret\r\n let secret = full.substring(0, this.secret_length)\r\n let hash = (await crypto.hash(secret)).substring(0, this.secret_length)\r\n return { full, secret, hash }\r\n }\r\n\r\n protected async url(path: string) {\r\n const secret = await this.getSecret()\r\n const base = this.config.url;\r\n if (path === '/') path = ''\r\n path = path.trim();\r\n path = path.startsWith('/') ? path.substring(1) : path\r\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\r\n if (path) path = `/${path}`\r\n return new URL(`${base}/${secret.hash}${path}`);\r\n }\r\n\r\n protected async getHeaders(path: string, init?: HttpRequestInit) {\r\n const url = await this.url(path)\r\n const secret = await this.getSecret()\r\n let headers: any = {};\r\n if (this.handshakeInfo) {\r\n headers[\"X-SIGNETURE\"] = await crypto.encrypt({\r\n signeture: this.handshakeInfo?.signeture,\r\n expire: Date.now() + this.handshakeInfo!.timeDiffarenc + 10000 // 10 seconds\r\n }, secret.secret) || '';\r\n }\r\n\r\n headers = {\r\n ...this.config?.defaultOptions?.headers,\r\n ...init?.headers,\r\n ...headers,\r\n 'Content-Type': this.CONTENT_TYPE,\r\n \"X-ORIGIN\": url.origin,\r\n \"X-METHOD\": (init?.method || 'GET').toUpperCase()\r\n }\r\n\r\n return headers;\r\n }\r\n\r\n protected async awaitForHandshake() {\r\n if (this.loadingHandshake) {\r\n await new Promise((resolve) => {\r\n const interval = setInterval(() => {\r\n if (!this.loadingHandshake) {\r\n clearInterval(interval);\r\n resolve(null);\r\n }\r\n }, 100);\r\n })\r\n }\r\n if (!this.handshakeInfo) {\r\n await this.handshake();\r\n }\r\n }\r\n\r\n async handshake() {\r\n await this.hooksCall('beforeHandshake');\r\n this.handshakeInfo = null;\r\n this.loadingHandshake = true;\r\n\r\n let max = this.config.secret.length\r\n let min = Math.floor(max / 4) * 3\r\n this.secret_length = Math.floor(Math.random() * (max - min + 1)) + min\r\n\r\n const secret = await this.getSecret()\r\n const res = await this.fetch('/', {\r\n method: 'POST',\r\n body: {\r\n hash: secret.hash,\r\n clientTime: new Date().toISOString(),\r\n secret: secret.secret,\r\n }\r\n })\r\n this.handshakeInfo = res.data\r\n this.loadingHandshake = false;\r\n await this.hooksCall('afterHandshake', this.handshakeInfo);\r\n }\r\n\r\n protected async fetch(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\r\n const isDev = path !== '/' && this.handshakeInfo?.dev\r\n const secret = await this.getSecret()\r\n const url = await this.url(path)\r\n let sparams = Object.fromEntries(url.searchParams.entries())\r\n const _init = { ...init }\r\n let params: any = {\r\n ...sparams,\r\n }\r\n\r\n if (Object.keys(sparams).length > 0) {\r\n for (let key in sparams) {\r\n url.searchParams.delete(key)\r\n }\r\n }\r\n\r\n if (_init?.params) {\r\n for (let key in _init.params) {\r\n params[key] = _init.params[key]\r\n }\r\n delete _init.params\r\n }\r\n\r\n if (Object.keys(params).length > 0) {\r\n if (isDev) {\r\n _init.params = params\r\n } else {\r\n const enc = await crypto.encrypt(params, secret.secret)\r\n url.href = url.href + \"?\" + encodeURIComponent(enc)\r\n }\r\n }\r\n\r\n const httpOption: any = {\r\n method: \"GET\",\r\n ...this.config?.defaultOptions,\r\n ..._init,\r\n headers: await this.getHeaders(path, _init)\r\n }\r\n\r\n if (httpOption?.body) {\r\n if (isDev) {\r\n httpOption.body = JSON.stringify(httpOption.body)\r\n } else {\r\n httpOption.body = await crypto.encryptBuffer(httpOption.body, secret.secret);\r\n }\r\n }\r\n const res = await xanFetch(url.href, httpOption)\r\n if (isDev) {\r\n const value = await res.text()\r\n const val = JSON.parse(value)\r\n return {\r\n success: res.ok,\r\n message: res.ok ? res.statusText : val,\r\n data: res.ok ? val : null,\r\n code: res.status\r\n }\r\n }\r\n const value = await res.arrayBuffer()\r\n const val = await crypto.decryptBuffer(new Uint8Array(value), secret.secret) as any\r\n\r\n return {\r\n success: res.ok,\r\n message: res.ok ? res.statusText : (val || res.statusText),\r\n data: res.ok ? val : null,\r\n code: res.status\r\n }\r\n }\r\n\r\n}\r\n\r\nexport default Base;\r\n"],"names":["crypto","xanFetch","Clients","Map","Base","constructor","config","this","loadingHandshake","secret_length","handshakeInfo","CONTENT_TYPE","Object","assign","url","URL","search","hash","Error","origin","pathname","has","hooksCall","hook","args","hooks","getSecret","full","secret","substring","path","base","trim","startsWith","endsWith","length","getHeaders","init","headers","encrypt","signeture","_a","expire","Date","now","timeDiffarenc","_b","defaultOptions","_c","method","toUpperCase","awaitForHandshake","Promise","resolve","interval","setInterval","clearInterval","handshake","max","min","Math","floor","random","res","fetch","body","clientTime","toISOString","data","isDev","dev","sparams","fromEntries","searchParams","entries","_init","params","keys","key","delete","enc","href","encodeURIComponent","httpOption","JSON","stringify","encryptBuffer","value","text","val","parse","success","ok","message","statusText","code","status","arrayBuffer","decryptBuffer","Uint8Array"],"mappings":"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"}
|
package/client/index.d.ts
CHANGED
|
@@ -3,7 +3,8 @@ import Base from './Base.js';
|
|
|
3
3
|
|
|
4
4
|
declare class SecurequClient extends Base {
|
|
5
5
|
send(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse>;
|
|
6
|
-
|
|
6
|
+
uploadFile(file: File, onProgress?: (p: number) => void): Promise<SecurequClientResponse>;
|
|
7
|
+
deleteFile(fileId: string, init?: Omit<HttpRequestInit, 'body' | 'method'>): Promise<SecurequClientResponse>;
|
|
7
8
|
get(path: string, init?: Omit<HttpRequestInit, 'body' | 'method'>): Promise<SecurequClientResponse>;
|
|
8
9
|
post(path: string, init?: Omit<HttpRequestInit, 'method'>): Promise<SecurequClientResponse>;
|
|
9
10
|
put(path: string, init?: Omit<HttpRequestInit, 'method'>): Promise<SecurequClientResponse>;
|
package/client/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("tslib"),t=require("../include/File.js"),a=require("./Base.js"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("tslib"),t=require("../include/File.js"),a=require("./Base.js"),i=require("../include/FileScaner.js");class s extends a.default{async send(e,t){await this.awaitForHandshake(),t=await this.hooksCall("beforeRequest",e,t)||t;if("/"===(await this.url(e)).pathname)throw new Error("Path is not allowed");for(let e in null==t?void 0:t.body)(null==t?void 0:t.body[e])instanceof File&&(t.body[e]=await this.uploadFile(t.body[e],null==t?void 0:t.onProgress));const a=await this.fetch(e,t);return["Signeture expired","Request expired"].includes(a.message)?(await this.handshake(),await this.send(e,t)):(await this.hooksCall("afterResponse",a),a)}async uploadFile(a,s){var n,o,l,r,d,h,u;await this.awaitForHandshake();const c=await t.getFileId(a),w=new AbortController;let f=await this.hooksCall("beforeUpload",a,c)||a;const k=null===(d=this.handshakeInfo)||void 0===d?void 0:d.maxFileSize;if(k&&f.size>1024*k)throw new Error(`File size exceeds the limit of ${k/1024} MB`);const p=null===(h=this.handshakeInfo)||void 0===h?void 0:h.chunkSize,y={fileId:c,name:f.name,size:f.size,type:f.type,totalChunks:t.totalChunks(f,p),chunkIndex:0,isFinish:!1},g=async()=>{await this.deleteFile(c),w.abort(),window.removeEventListener("pagehide",g)};window.addEventListener("pagehide",g);try{for(var b,v=!0,m=e.__asyncValues(t.chunkFile(f,p));!(n=(b=await m.next()).done);){r=b.value,v=!1;try{let{chunk:e,chunkIndex:t}=r;if(0===t&&(null===(u=this.handshakeInfo)||void 0===u?void 0:u.checkFileType)&&!i.fileScaner(e))return await g(),{success:!1,message:"Unknown or unsupported file type",data:null,code:0};y.chunkIndex=t,y.isFinish=t+1===y.totalChunks;const n={method:"PUT",signal:w.signal,body:{chunk:e,filemeta:y},onProgress:e=>{if(s){const a=Math.floor((t+1)/y.totalChunks*100),i=Math.floor(e/100/y.totalChunks*100);s(Math.min(a+i,100))}}};await this.hooksCall("beforeUploadChunk",e,y);let o=await this.fetch("/",n);if(!o.success){if(!["Signeture expired","Request expired"].includes(o.message))return await g(),o;await this.handshake(),window.removeEventListener("pagehide",g),o=await this.uploadFile(a,s)}await this.hooksCall("afterUploadChunk",o,y)}finally{v=!0}}}catch(e){o={error:e}}finally{try{v||n||!(l=m.return)||await l.call(m)}finally{if(o)throw o.error}}window.removeEventListener("pagehide",g);const F={success:!0,message:"File uploaded successfully",data:y,code:200};return await this.hooksCall("afterUpload",F,f),F}async deleteFile(e,t){await this.awaitForHandshake();const a=await this.fetch("/",Object.assign(Object.assign({},t),{method:"DELETE",body:{fileId:e}}));return["Signeture expired","Request expired"].includes(a.message)?(await this.handshake(),await this.deleteFile(e,t)):a}async get(e,t){return await this.send(e,t)}async post(e,t){return await this.send(e,Object.assign(Object.assign({},t),{method:"POST"}))}async put(e,t){return await this.send(e,Object.assign(Object.assign({},t),{method:"PUT"}))}async delete(e,t){return await this.send(e,Object.assign(Object.assign({},t),{method:"DELETE"}))}}exports.default=s;//# sourceMappingURL=index.js.map
|
package/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/client/index.ts"],"sourcesContent":["import { HttpRequestInit, SecurequClientResponse } from \"./types\";\r\nimport { chunkFile, getFileId, totalChunks } from \"../include/File\";\r\nimport Base from \"./Base\";\r\nimport fileScaner from '../include/FileScaner';\r\n\r\nclass SecurequClient extends Base {\r\n\r\n async send(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\r\n await this.awaitForHandshake();\r\n init = await this.hooksCall('beforeRequest', path, init) || init;\r\n const url = await this.url(path)\r\n if (url.pathname === '/') throw new Error(\"Path is not allowed\")\r\n\r\n for (let key in init?.body) {\r\n if (init?.body[key] instanceof File) {\r\n init.body[key] = await this.
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/client/index.ts"],"sourcesContent":["import { HttpRequestInit, SecurequClientResponse } from \"./types\";\r\nimport { chunkFile, getFileId, totalChunks } from \"../include/File\";\r\nimport Base from \"./Base\";\r\nimport fileScaner from '../include/FileScaner';\r\nimport { UploadFileMeta } from \"../server/types\";\r\n\r\nclass SecurequClient extends Base {\r\n\r\n async send(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\r\n await this.awaitForHandshake();\r\n init = await this.hooksCall('beforeRequest', path, init) || init;\r\n const url = await this.url(path)\r\n if (url.pathname === '/') throw new Error(\"Path is not allowed\")\r\n\r\n for (let key in init?.body) {\r\n if (init?.body[key] instanceof File) {\r\n init.body[key] = await this.uploadFile(init.body[key], init?.onProgress)\r\n }\r\n }\r\n\r\n const res = await this.fetch(path, init);\r\n if ([\"Signeture expired\", \"Request expired\"].includes(res.message)) {\r\n await this.handshake();\r\n return await this.send(path, init);\r\n }\r\n await this.hooksCall('afterResponse', res);\r\n return res;\r\n }\r\n\r\n async uploadFile(file: File, onProgress?: (p: number) => void): Promise<SecurequClientResponse> {\r\n await this.awaitForHandshake();\r\n const fileId = await getFileId(file);\r\n const controller = new AbortController();\r\n\r\n let _file = await this.hooksCall('beforeUpload', file, fileId) || file;\r\n const maxFileSize = this.handshakeInfo?.maxFileSize\r\n if (maxFileSize && _file.size > maxFileSize * 1024) {\r\n throw new Error(`File size exceeds the limit of ${maxFileSize / 1024} MB`)\r\n }\r\n\r\n const chunkSize = this.handshakeInfo?.chunkSize\r\n\r\n // send metadata\r\n const filemeta: UploadFileMeta = {\r\n fileId: fileId,\r\n name: _file.name,\r\n size: _file.size,\r\n type: _file.type,\r\n totalChunks: totalChunks(_file, chunkSize),\r\n chunkIndex: 0,\r\n isFinish: false\r\n }\r\n\r\n const abort = async () => {\r\n await this.deleteFile(fileId);\r\n controller.abort();\r\n window.removeEventListener(\"pagehide\", abort);\r\n }\r\n\r\n window.addEventListener(\"pagehide\", abort);\r\n\r\n for await (let { chunk, chunkIndex } of chunkFile(_file, chunkSize)) {\r\n if (chunkIndex === 0 && this.handshakeInfo?.checkFileType && !fileScaner(chunk)) {\r\n await abort()\r\n return {\r\n success: false,\r\n message: \"Unknown or unsupported file type\",\r\n data: null,\r\n code: 0\r\n }\r\n }\r\n\r\n filemeta.chunkIndex = chunkIndex;\r\n filemeta.isFinish = chunkIndex + 1 === filemeta.totalChunks;\r\n\r\n const info: any = {\r\n method: 'PUT',\r\n signal: controller.signal,\r\n body: {\r\n chunk,\r\n filemeta\r\n },\r\n onProgress: (p: number) => {\r\n if (onProgress) {\r\n const totalProgress = Math.floor(((chunkIndex + 1) / filemeta.totalChunks) * 100)\r\n const currentProgress = Math.floor((p / 100) / filemeta.totalChunks * 100)\r\n onProgress(Math.min(totalProgress + currentProgress, 100))\r\n }\r\n }\r\n }\r\n await this.hooksCall('beforeUploadChunk', chunk, filemeta);\r\n\r\n let res = await this.fetch('/', info)\r\n\r\n if (!res.success) {\r\n if ([\"Signeture expired\", \"Request expired\"].includes(res.message)) {\r\n await this.handshake();\r\n window.removeEventListener(\"pagehide\", abort);\r\n res = await this.uploadFile(file, onProgress);\r\n } else {\r\n await abort()\r\n return res\r\n }\r\n }\r\n await this.hooksCall('afterUploadChunk', res, filemeta);\r\n }\r\n\r\n window.removeEventListener(\"pagehide\", abort);\r\n\r\n const info = {\r\n success: true,\r\n message: 'File uploaded successfully',\r\n data: filemeta,\r\n code: 200\r\n }\r\n await this.hooksCall('afterUpload', info, _file);\r\n return info\r\n }\r\n\r\n async deleteFile(fileId: string, init?: Omit<HttpRequestInit, 'body' | 'method'>): Promise<SecurequClientResponse> {\r\n await this.awaitForHandshake();\r\n const res = await this.fetch('/', {\r\n ...init,\r\n method: 'DELETE',\r\n body: { fileId }\r\n });\r\n if ([\"Signeture expired\", \"Request expired\"].includes(res.message)) {\r\n await this.handshake();\r\n return await this.deleteFile(fileId, init);\r\n }\r\n return res;\r\n }\r\n\r\n async get(path: string, init?: Omit<HttpRequestInit, 'body' | 'method'>) {\r\n return await this.send(path, init);\r\n }\r\n\r\n async post(path: string, init?: Omit<HttpRequestInit, 'method'>) {\r\n return await this.send(path, { ...init, method: \"POST\" });\r\n }\r\n\r\n async put(path: string, init?: Omit<HttpRequestInit, 'method'>) {\r\n return await this.send(path, { ...init, method: \"PUT\" });\r\n }\r\n\r\n async delete(path: string, init?: Omit<HttpRequestInit, 'method'>) {\r\n return await this.send(path, { ...init, method: \"DELETE\" });\r\n }\r\n\r\n}\r\n\r\nexport default SecurequClient;\r\n"],"names":["SecurequClient","Base","send","path","init","this","awaitForHandshake","hooksCall","url","pathname","Error","key","body","File","uploadFile","onProgress","res","fetch","includes","message","handshake","file","fileId","getFileId","controller","AbortController","_file","maxFileSize","_d","handshakeInfo","size","chunkSize","_e","filemeta","name","type","totalChunks","chunkIndex","isFinish","abort","async","deleteFile","window","removeEventListener","addEventListener","_j","_g","_h","__asyncValues","chunkFile","_a","next","done","_c","value","chunk","_f","checkFileType","fileScaner","success","data","code","info","method","signal","p","totalProgress","Math","floor","currentProgress","min","Object","assign","get","post","put","exports","default"],"mappings":"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"}
|
package/client/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{__asyncValues as e}from"tslib";import{getFileId as t,totalChunks as a,chunkFile as
|
|
1
|
+
import{__asyncValues as e}from"tslib";import{getFileId as t,totalChunks as a,chunkFile as i}from"../include/File.mjs";import s from"./Base.mjs";import{fileScaner as n}from"../include/FileScaner.mjs";class o extends s{async send(e,t){await this.awaitForHandshake(),t=await this.hooksCall("beforeRequest",e,t)||t;if("/"===(await this.url(e)).pathname)throw new Error("Path is not allowed");for(let e in null==t?void 0:t.body)(null==t?void 0:t.body[e])instanceof File&&(t.body[e]=await this.uploadFile(t.body[e],null==t?void 0:t.onProgress));const a=await this.fetch(e,t);return["Signeture expired","Request expired"].includes(a.message)?(await this.handshake(),await this.send(e,t)):(await this.hooksCall("afterResponse",a),a)}async uploadFile(s,o){var l,r,h,d,c,u,w;await this.awaitForHandshake();const f=await t(s),p=new AbortController;let m=await this.hooksCall("beforeUpload",s,f)||s;const k=null===(c=this.handshakeInfo)||void 0===c?void 0:c.maxFileSize;if(k&&m.size>1024*k)throw new Error(`File size exceeds the limit of ${k/1024} MB`);const g=null===(u=this.handshakeInfo)||void 0===u?void 0:u.chunkSize,y={fileId:f,name:m.name,size:m.size,type:m.type,totalChunks:a(m,g),chunkIndex:0,isFinish:!1},b=async()=>{await this.deleteFile(f),p.abort(),window.removeEventListener("pagehide",b)};window.addEventListener("pagehide",b);try{for(var v,F=!0,x=e(i(m,g));!(l=(v=await x.next()).done);){d=v.value,F=!1;try{let{chunk:e,chunkIndex:t}=d;if(0===t&&(null===(w=this.handshakeInfo)||void 0===w?void 0:w.checkFileType)&&!n(e))return await b(),{success:!1,message:"Unknown or unsupported file type",data:null,code:0};y.chunkIndex=t,y.isFinish=t+1===y.totalChunks;const a={method:"PUT",signal:p.signal,body:{chunk:e,filemeta:y},onProgress:e=>{if(o){const a=Math.floor((t+1)/y.totalChunks*100),i=Math.floor(e/100/y.totalChunks*100);o(Math.min(a+i,100))}}};await this.hooksCall("beforeUploadChunk",e,y);let i=await this.fetch("/",a);if(!i.success){if(!["Signeture expired","Request expired"].includes(i.message))return await b(),i;await this.handshake(),window.removeEventListener("pagehide",b),i=await this.uploadFile(s,o)}await this.hooksCall("afterUploadChunk",i,y)}finally{F=!0}}}catch(e){r={error:e}}finally{try{F||l||!(h=x.return)||await h.call(x)}finally{if(r)throw r.error}}window.removeEventListener("pagehide",b);const C={success:!0,message:"File uploaded successfully",data:y,code:200};return await this.hooksCall("afterUpload",C,m),C}async deleteFile(e,t){await this.awaitForHandshake();const a=await this.fetch("/",Object.assign(Object.assign({},t),{method:"DELETE",body:{fileId:e}}));return["Signeture expired","Request expired"].includes(a.message)?(await this.handshake(),await this.deleteFile(e,t)):a}async get(e,t){return await this.send(e,t)}async post(e,t){return await this.send(e,Object.assign(Object.assign({},t),{method:"POST"}))}async put(e,t){return await this.send(e,Object.assign(Object.assign({},t),{method:"PUT"}))}async delete(e,t){return await this.send(e,Object.assign(Object.assign({},t),{method:"DELETE"}))}}export{o as default};//# sourceMappingURL=index.mjs.map
|
package/client/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../../src/client/index.ts"],"sourcesContent":["import { HttpRequestInit, SecurequClientResponse } from \"./types\";\r\nimport { chunkFile, getFileId, totalChunks } from \"../include/File\";\r\nimport Base from \"./Base\";\r\nimport fileScaner from '../include/FileScaner';\r\n\r\nclass SecurequClient extends Base {\r\n\r\n async send(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\r\n await this.awaitForHandshake();\r\n init = await this.hooksCall('beforeRequest', path, init) || init;\r\n const url = await this.url(path)\r\n if (url.pathname === '/') throw new Error(\"Path is not allowed\")\r\n\r\n for (let key in init?.body) {\r\n if (init?.body[key] instanceof File) {\r\n init.body[key] = await this.
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../src/client/index.ts"],"sourcesContent":["import { HttpRequestInit, SecurequClientResponse } from \"./types\";\r\nimport { chunkFile, getFileId, totalChunks } from \"../include/File\";\r\nimport Base from \"./Base\";\r\nimport fileScaner from '../include/FileScaner';\r\nimport { UploadFileMeta } from \"../server/types\";\r\n\r\nclass SecurequClient extends Base {\r\n\r\n async send(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\r\n await this.awaitForHandshake();\r\n init = await this.hooksCall('beforeRequest', path, init) || init;\r\n const url = await this.url(path)\r\n if (url.pathname === '/') throw new Error(\"Path is not allowed\")\r\n\r\n for (let key in init?.body) {\r\n if (init?.body[key] instanceof File) {\r\n init.body[key] = await this.uploadFile(init.body[key], init?.onProgress)\r\n }\r\n }\r\n\r\n const res = await this.fetch(path, init);\r\n if ([\"Signeture expired\", \"Request expired\"].includes(res.message)) {\r\n await this.handshake();\r\n return await this.send(path, init);\r\n }\r\n await this.hooksCall('afterResponse', res);\r\n return res;\r\n }\r\n\r\n async uploadFile(file: File, onProgress?: (p: number) => void): Promise<SecurequClientResponse> {\r\n await this.awaitForHandshake();\r\n const fileId = await getFileId(file);\r\n const controller = new AbortController();\r\n\r\n let _file = await this.hooksCall('beforeUpload', file, fileId) || file;\r\n const maxFileSize = this.handshakeInfo?.maxFileSize\r\n if (maxFileSize && _file.size > maxFileSize * 1024) {\r\n throw new Error(`File size exceeds the limit of ${maxFileSize / 1024} MB`)\r\n }\r\n\r\n const chunkSize = this.handshakeInfo?.chunkSize\r\n\r\n // send metadata\r\n const filemeta: UploadFileMeta = {\r\n fileId: fileId,\r\n name: _file.name,\r\n size: _file.size,\r\n type: _file.type,\r\n totalChunks: totalChunks(_file, chunkSize),\r\n chunkIndex: 0,\r\n isFinish: false\r\n }\r\n\r\n const abort = async () => {\r\n await this.deleteFile(fileId);\r\n controller.abort();\r\n window.removeEventListener(\"pagehide\", abort);\r\n }\r\n\r\n window.addEventListener(\"pagehide\", abort);\r\n\r\n for await (let { chunk, chunkIndex } of chunkFile(_file, chunkSize)) {\r\n if (chunkIndex === 0 && this.handshakeInfo?.checkFileType && !fileScaner(chunk)) {\r\n await abort()\r\n return {\r\n success: false,\r\n message: \"Unknown or unsupported file type\",\r\n data: null,\r\n code: 0\r\n }\r\n }\r\n\r\n filemeta.chunkIndex = chunkIndex;\r\n filemeta.isFinish = chunkIndex + 1 === filemeta.totalChunks;\r\n\r\n const info: any = {\r\n method: 'PUT',\r\n signal: controller.signal,\r\n body: {\r\n chunk,\r\n filemeta\r\n },\r\n onProgress: (p: number) => {\r\n if (onProgress) {\r\n const totalProgress = Math.floor(((chunkIndex + 1) / filemeta.totalChunks) * 100)\r\n const currentProgress = Math.floor((p / 100) / filemeta.totalChunks * 100)\r\n onProgress(Math.min(totalProgress + currentProgress, 100))\r\n }\r\n }\r\n }\r\n await this.hooksCall('beforeUploadChunk', chunk, filemeta);\r\n\r\n let res = await this.fetch('/', info)\r\n\r\n if (!res.success) {\r\n if ([\"Signeture expired\", \"Request expired\"].includes(res.message)) {\r\n await this.handshake();\r\n window.removeEventListener(\"pagehide\", abort);\r\n res = await this.uploadFile(file, onProgress);\r\n } else {\r\n await abort()\r\n return res\r\n }\r\n }\r\n await this.hooksCall('afterUploadChunk', res, filemeta);\r\n }\r\n\r\n window.removeEventListener(\"pagehide\", abort);\r\n\r\n const info = {\r\n success: true,\r\n message: 'File uploaded successfully',\r\n data: filemeta,\r\n code: 200\r\n }\r\n await this.hooksCall('afterUpload', info, _file);\r\n return info\r\n }\r\n\r\n async deleteFile(fileId: string, init?: Omit<HttpRequestInit, 'body' | 'method'>): Promise<SecurequClientResponse> {\r\n await this.awaitForHandshake();\r\n const res = await this.fetch('/', {\r\n ...init,\r\n method: 'DELETE',\r\n body: { fileId }\r\n });\r\n if ([\"Signeture expired\", \"Request expired\"].includes(res.message)) {\r\n await this.handshake();\r\n return await this.deleteFile(fileId, init);\r\n }\r\n return res;\r\n }\r\n\r\n async get(path: string, init?: Omit<HttpRequestInit, 'body' | 'method'>) {\r\n return await this.send(path, init);\r\n }\r\n\r\n async post(path: string, init?: Omit<HttpRequestInit, 'method'>) {\r\n return await this.send(path, { ...init, method: \"POST\" });\r\n }\r\n\r\n async put(path: string, init?: Omit<HttpRequestInit, 'method'>) {\r\n return await this.send(path, { ...init, method: \"PUT\" });\r\n }\r\n\r\n async delete(path: string, init?: Omit<HttpRequestInit, 'method'>) {\r\n return await this.send(path, { ...init, method: \"DELETE\" });\r\n }\r\n\r\n}\r\n\r\nexport default SecurequClient;\r\n"],"names":["SecurequClient","Base","send","path","init","this","awaitForHandshake","hooksCall","url","pathname","Error","key","body","File","uploadFile","onProgress","res","fetch","includes","message","handshake","file","fileId","getFileId","controller","AbortController","_file","maxFileSize","_d","handshakeInfo","size","chunkSize","_e","filemeta","name","type","totalChunks","chunkIndex","isFinish","abort","async","deleteFile","window","removeEventListener","addEventListener","_j","_g","_h","__asyncValues","chunkFile","_a","next","done","_c","value","chunk","_f","checkFileType","fileScaner","success","data","code","info","method","signal","p","totalProgress","Math","floor","currentProgress","min","Object","assign","get","post","put"],"mappings":"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"}
|
package/client/types.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { XanFetchOptions } from 'xanfetch/types';
|
|
2
|
+
import { UploadFileMeta } from '../server/types.js';
|
|
2
3
|
|
|
3
4
|
type HandshakeInfo = {
|
|
5
|
+
dev: boolean;
|
|
4
6
|
timeDiffarenc: number;
|
|
5
7
|
signeture: string;
|
|
6
8
|
maxFileSize: number | null;
|
|
7
|
-
dev: boolean;
|
|
8
9
|
checkFileType: boolean;
|
|
10
|
+
chunkSize?: number;
|
|
9
11
|
};
|
|
10
|
-
type Kilobyte = number;
|
|
11
12
|
type SecurequClientConfig = {
|
|
12
13
|
url: string;
|
|
13
14
|
secret: string;
|
|
14
15
|
defaultOptions?: XanFetchOptions;
|
|
15
|
-
chunkSize?: Kilobyte;
|
|
16
16
|
hooks?: {
|
|
17
17
|
beforeHandshake?: () => Promise<void> | void;
|
|
18
18
|
afterHandshake?: (info: HandshakeInfo) => Promise<void> | void;
|
|
@@ -20,8 +20,8 @@ type SecurequClientConfig = {
|
|
|
20
20
|
afterResponse?: (response: Response) => Promise<void> | void;
|
|
21
21
|
beforeUpload?: (file: File, fileId: string) => Promise<File> | void;
|
|
22
22
|
afterUpload?: (response: SecurequClientResponse, file: File) => Promise<void> | void;
|
|
23
|
-
beforeUploadChunk?: (chunk: Blob,
|
|
24
|
-
afterUploadChunk?: (response: SecurequClientResponse,
|
|
23
|
+
beforeUploadChunk?: (chunk: Blob, filemeta: UploadFileMeta) => Promise<void> | void;
|
|
24
|
+
afterUploadChunk?: (response: SecurequClientResponse, filemeta: UploadFileMeta) => Promise<void> | void;
|
|
25
25
|
};
|
|
26
26
|
};
|
|
27
27
|
type SecurequClientResponse = {
|
package/include/File.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("tslib"),t=require("./crypto.js");function n(e){return e<=
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("tslib"),t=require("./crypto.js");function n(e){const t=1048576;return e<=1*t?65536:e<=10*t?262144:e<=100*t?524288:e<=500*t?1*t:e<=2048*t?2*t:4*t}exports.chunkFile=function(t,i){return e.__asyncGenerator(this,arguments,function*(){const r=t.size;i=i||n(r);let o=0;for(;o<r;){const n=t.slice(o,o+i),r=new Uint8Array(yield e.__await(n.arrayBuffer()));yield yield e.__await({chunk:r,chunkIndex:Math.floor(o/i)}),o+=i}})},exports.getChunkSize=n,exports.getFileId=async function(e){const n=[navigator.userAgent,navigator.language,screen.width,screen.height,screen.colorDepth,(new Date).getTimezoneOffset(),Intl.DateTimeFormat().resolvedOptions().timeZone||""].join("||"),i=`${e.name}||${e.size}||${e.lastModified}||${n}`,r=e.name.split(".").pop()||"";return`${await t.default.hash(i)}.${r}`},exports.totalChunks=(e,t)=>Math.ceil(e.size/(t||n(e.size)));//# sourceMappingURL=File.js.map
|
package/include/File.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"File.js","sources":["../../src/include/File.ts"],"sourcesContent":["import crypto from \"./crypto\";\r\n\r\
|
|
1
|
+
{"version":3,"file":"File.js","sources":["../../src/include/File.ts"],"sourcesContent":["import crypto from \"./crypto\";\r\n\r\nexport function getChunkSize(fileSize: number): number {\r\n // fileSize in bytes\r\n const MB = 1024 * 1024;\r\n\r\n if (fileSize <= 1 * MB) {\r\n // Very small files (<1MB): single small chunk\r\n return 64 * 1024; // 64 KB\r\n } else if (fileSize <= 10 * MB) {\r\n // Small files (1–10MB): medium chunks\r\n return 256 * 1024; // 256 KB\r\n } else if (fileSize <= 100 * MB) {\r\n // Medium files (10–100MB): faster upload, moderate size\r\n return 512 * 1024; // 512 KB\r\n } else if (fileSize <= 500 * MB) {\r\n // Large files (100–500MB): larger chunks to reduce overhead\r\n return 1 * MB; // 1 MB\r\n } else if (fileSize <= 2 * 1024 * MB) {\r\n // Very large files (500MB–2GB): fewer but larger parts\r\n return 2 * MB; // 2 MB\r\n } else {\r\n // Extremely large files (>2GB)\r\n return 4 * MB; // 4 MB max chunk size\r\n }\r\n}\r\n\r\nexport const totalChunks = (file: File, chunkSize?: number) => Math.ceil(file.size / (chunkSize || getChunkSize(file.size)));\r\n\r\nexport async function* chunkFile(file: File, chunkSize?: number) {\r\n const fileSize = file.size;\r\n chunkSize = chunkSize || getChunkSize(fileSize);\r\n let offset = 0;\r\n\r\n while (offset < fileSize) {\r\n const chunk = file.slice(offset, offset + chunkSize);\r\n const buffer = new Uint8Array(await chunk.arrayBuffer());\r\n yield { chunk: buffer, chunkIndex: Math.floor(offset / chunkSize) };\r\n offset += chunkSize;\r\n }\r\n}\r\n\r\n\r\nexport async function getFileId(file: File): Promise<string> {\r\n const data = [\r\n navigator.userAgent,\r\n navigator.language,\r\n screen.width,\r\n screen.height,\r\n screen.colorDepth,\r\n new Date().getTimezoneOffset(),\r\n Intl.DateTimeFormat().resolvedOptions().timeZone || \"\"\r\n ].join(\"||\");\r\n\r\n const meta = `${file.name}||${file.size}||${file.lastModified}||${data}`\r\n const ext = file.name.split('.').pop() || ''\r\n const id = await crypto.hash(meta);\r\n return `${id}.${ext}`;\r\n}"],"names":["getChunkSize","fileSize","MB","exports","chunkFile","file","chunkSize","size","offset","chunk","slice","buffer","Uint8Array","__await","arrayBuffer","chunkIndex","Math","floor","getFileId","async","data","navigator","userAgent","language","screen","width","height","colorDepth","Date","getTimezoneOffset","Intl","DateTimeFormat","resolvedOptions","timeZone","join","meta","name","lastModified","ext","split","pop","crypto","hash","totalChunks","ceil"],"mappings":"oHAEM,SAAUA,EAAaC,GAE1B,MAAMC,EAAK,QAEX,OAAID,GAAY,EAAIC,EAEV,MACCD,GAAY,GAAKC,EAElB,OACCD,GAAY,IAAMC,EAEnB,OACCD,GAAY,IAAMC,EAEnB,EAAIA,EACHD,GAAY,KAAWC,EAExB,EAAIA,EAGJ,EAAIA,CAEjB,CAiCAC,QAAAC,UA7BM,SAA2BC,EAAYC,wDAC1C,MAAML,EAAWI,EAAKE,KACtBD,EAAYA,GAAaN,EAAaC,GACtC,IAAIO,EAAS,EAEb,KAAOA,EAASP,GAAU,CACvB,MAAMQ,EAAQJ,EAAKK,MAAMF,EAAQA,EAASF,GACpCK,EAAS,IAAIC,iBAAWC,EAAAA,QAAMJ,EAAMK,4BAC1CD,EAAAA,QAAM,CAAEJ,MAAOE,EAAQI,WAAYC,KAAKC,MAAMT,EAASF,KACvDE,GAAUF,CACZ,CACJ,EAAC,EAkBDH,QAAAH,aAAAA,EAAAG,QAAAe,UAfOC,eAAyBd,GAC7B,MAAMe,EAAO,CACVC,UAAUC,UACVD,UAAUE,SACVC,OAAOC,MACPD,OAAOE,OACPF,OAAOG,YACP,IAAIC,MAAOC,oBACXC,KAAKC,iBAAiBC,kBAAkBC,UAAY,IACrDC,KAAK,MAEDC,EAAO,GAAG9B,EAAK+B,SAAS/B,EAAKE,SAASF,EAAKgC,iBAAiBjB,IAC5DkB,EAAMjC,EAAK+B,KAAKG,MAAM,KAAKC,OAAS,GAE1C,MAAO,SADUC,EAAAA,QAAOC,KAAKP,MACbG,GACnB,EAAAnC,QAAAwC,YA/B2B,CAACtC,EAAYC,IAAuBU,KAAK4B,KAAKvC,EAAKE,MAAQD,GAAaN,EAAaK,EAAKE"}
|
package/include/File.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{__asyncGenerator as e,__await as t}from"tslib";import n from"./crypto.mjs";function i(e){return e<=
|
|
1
|
+
import{__asyncGenerator as e,__await as t}from"tslib";import n from"./crypto.mjs";function i(e){const t=1048576;return e<=1*t?65536:e<=10*t?262144:e<=100*t?524288:e<=500*t?1*t:e<=2048*t?2*t:4*t}const o=(e,t)=>Math.ceil(e.size/(t||i(e.size)));function r(n,o){return e(this,arguments,function*(){const e=n.size;o=o||i(e);let r=0;for(;r<e;){const e=n.slice(r,r+o),i=new Uint8Array(yield t(e.arrayBuffer()));yield yield t({chunk:i,chunkIndex:Math.floor(r/o)}),r+=o}})}async function s(e){const t=[navigator.userAgent,navigator.language,screen.width,screen.height,screen.colorDepth,(new Date).getTimezoneOffset(),Intl.DateTimeFormat().resolvedOptions().timeZone||""].join("||"),i=`${e.name}||${e.size}||${e.lastModified}||${t}`,o=e.name.split(".").pop()||"";return`${await n.hash(i)}.${o}`}export{r as chunkFile,i as getChunkSize,s as getFileId,o as totalChunks};//# sourceMappingURL=File.mjs.map
|
package/include/File.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"File.mjs","sources":["../../src/include/File.ts"],"sourcesContent":["import crypto from \"./crypto\";\r\n\r\
|
|
1
|
+
{"version":3,"file":"File.mjs","sources":["../../src/include/File.ts"],"sourcesContent":["import crypto from \"./crypto\";\r\n\r\nexport function getChunkSize(fileSize: number): number {\r\n // fileSize in bytes\r\n const MB = 1024 * 1024;\r\n\r\n if (fileSize <= 1 * MB) {\r\n // Very small files (<1MB): single small chunk\r\n return 64 * 1024; // 64 KB\r\n } else if (fileSize <= 10 * MB) {\r\n // Small files (1–10MB): medium chunks\r\n return 256 * 1024; // 256 KB\r\n } else if (fileSize <= 100 * MB) {\r\n // Medium files (10–100MB): faster upload, moderate size\r\n return 512 * 1024; // 512 KB\r\n } else if (fileSize <= 500 * MB) {\r\n // Large files (100–500MB): larger chunks to reduce overhead\r\n return 1 * MB; // 1 MB\r\n } else if (fileSize <= 2 * 1024 * MB) {\r\n // Very large files (500MB–2GB): fewer but larger parts\r\n return 2 * MB; // 2 MB\r\n } else {\r\n // Extremely large files (>2GB)\r\n return 4 * MB; // 4 MB max chunk size\r\n }\r\n}\r\n\r\nexport const totalChunks = (file: File, chunkSize?: number) => Math.ceil(file.size / (chunkSize || getChunkSize(file.size)));\r\n\r\nexport async function* chunkFile(file: File, chunkSize?: number) {\r\n const fileSize = file.size;\r\n chunkSize = chunkSize || getChunkSize(fileSize);\r\n let offset = 0;\r\n\r\n while (offset < fileSize) {\r\n const chunk = file.slice(offset, offset + chunkSize);\r\n const buffer = new Uint8Array(await chunk.arrayBuffer());\r\n yield { chunk: buffer, chunkIndex: Math.floor(offset / chunkSize) };\r\n offset += chunkSize;\r\n }\r\n}\r\n\r\n\r\nexport async function getFileId(file: File): Promise<string> {\r\n const data = [\r\n navigator.userAgent,\r\n navigator.language,\r\n screen.width,\r\n screen.height,\r\n screen.colorDepth,\r\n new Date().getTimezoneOffset(),\r\n Intl.DateTimeFormat().resolvedOptions().timeZone || \"\"\r\n ].join(\"||\");\r\n\r\n const meta = `${file.name}||${file.size}||${file.lastModified}||${data}`\r\n const ext = file.name.split('.').pop() || ''\r\n const id = await crypto.hash(meta);\r\n return `${id}.${ext}`;\r\n}"],"names":["getChunkSize","fileSize","MB","totalChunks","file","chunkSize","Math","ceil","size","chunkFile","offset","chunk","slice","buffer","Uint8Array","__await","arrayBuffer","chunkIndex","floor","async","getFileId","data","navigator","userAgent","language","screen","width","height","colorDepth","Date","getTimezoneOffset","Intl","DateTimeFormat","resolvedOptions","timeZone","join","meta","name","lastModified","ext","split","pop","crypto","hash"],"mappings":"kFAEM,SAAUA,EAAaC,GAE1B,MAAMC,EAAK,QAEX,OAAID,GAAY,EAAIC,EAEV,MACCD,GAAY,GAAKC,EAElB,OACCD,GAAY,IAAMC,EAEnB,OACCD,GAAY,IAAMC,EAEnB,EAAIA,EACHD,GAAY,KAAWC,EAExB,EAAIA,EAGJ,EAAIA,CAEjB,CAEO,MAAMC,EAAc,CAACC,EAAYC,IAAuBC,KAAKC,KAAKH,EAAKI,MAAQH,GAAaL,EAAaI,EAAKI,QAE/G,SAAiBC,EAAUL,EAAYC,uCAC1C,MAAMJ,EAAWG,EAAKI,KACtBH,EAAYA,GAAaL,EAAaC,GACtC,IAAIS,EAAS,EAEb,KAAOA,EAAST,GAAU,CACvB,MAAMU,EAAQP,EAAKQ,MAAMF,EAAQA,EAASL,GACpCQ,EAAS,IAAIC,iBAAWC,EAAMJ,EAAMK,4BAC1CD,EAAM,CAAEJ,MAAOE,EAAQI,WAAYX,KAAKY,MAAMR,EAASL,KACvDK,GAAUL,CACZ,CACJ,EAAC,CAGMc,eAAeC,EAAUhB,GAC7B,MAAMiB,EAAO,CACVC,UAAUC,UACVD,UAAUE,SACVC,OAAOC,MACPD,OAAOE,OACPF,OAAOG,YACP,IAAIC,MAAOC,oBACXC,KAAKC,iBAAiBC,kBAAkBC,UAAY,IACrDC,KAAK,MAEDC,EAAO,GAAGhC,EAAKiC,SAASjC,EAAKI,SAASJ,EAAKkC,iBAAiBjB,IAC5DkB,EAAMnC,EAAKiC,KAAKG,MAAM,KAAKC,OAAS,GAE1C,MAAO,SADUC,EAAOC,KAAKP,MACbG,GACnB,QAAA9B,eAAAT,kBAAAoB,eAAAjB"}
|
package/index.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ export { default as SecurequServer } from './server/index.js';
|
|
|
2
2
|
export { default as SecurequClient } from './client/index.js';
|
|
3
3
|
export { default as crypto } from './include/crypto.js';
|
|
4
4
|
export { default as compresor } from './include/compress.js';
|
|
5
|
-
export {
|
|
5
|
+
export { HandlerFunction, HandlerInfo, ListenerInfo, Metadata, RouteFactory, SecurequServerConfig, ServerClient, ServerClientInfo, ServerClientOrigin, ServerClientSecret, ServerResponse, UploadFileMeta, UploadFilePath } from './server/types.js';
|
|
6
6
|
export { HTTPMethods, HandshakeInfo, HttpRequestInit, SecurequClientConfig, SecurequClientResponse } from './client/types.js';
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -120,10 +120,11 @@ import { SecurequServer } from 'securequ';
|
|
|
120
120
|
const api = new SecurequServer({
|
|
121
121
|
mode: 'production',
|
|
122
122
|
basepath: '/api',
|
|
123
|
-
clients: [{ origin: 'https://app.example.com', secret: process.env.APP_CLIENT_SECRET! }],
|
|
123
|
+
clients: [{ origin: 'https://app.example.com' | "*", secret: process.env.APP_CLIENT_SECRET! }],
|
|
124
124
|
upload: {
|
|
125
125
|
chunk: async (chunk, meta) => { /* store chunk */ return true; },
|
|
126
|
-
complete: async (meta) => { /* stitch & persist */ return `/files/${meta.fileid}`; }
|
|
126
|
+
complete: async (meta) => { /* stitch & persist */ return `/files/${meta.fileid}`; },
|
|
127
|
+
failed: async (meta) => boolean
|
|
127
128
|
}
|
|
128
129
|
});
|
|
129
130
|
|
|
@@ -131,12 +132,9 @@ api.post('/echo', ({ body }) => { throw { ok: true, body }; });
|
|
|
131
132
|
|
|
132
133
|
const app = express();
|
|
133
134
|
app.use('/api/*', express.raw({ type: 'application/octet-stream', limit: '20mb' }), async (req, res) => {
|
|
134
|
-
const r = await api.listen({
|
|
135
|
-
signeture: req.headers['x-signeture'] as string,
|
|
136
|
-
path: req.originalUrl,
|
|
135
|
+
const r = await api.listen(req.originalUrl, {
|
|
137
136
|
body: req.body,
|
|
138
|
-
|
|
139
|
-
origin: req.headers['x-origin'] as string,
|
|
137
|
+
headers: req.headers,
|
|
140
138
|
}, req);
|
|
141
139
|
res.status(r.status).end(r.content);
|
|
142
140
|
});
|
|
@@ -192,7 +190,7 @@ server.get(path, handler)
|
|
|
192
190
|
server.post(path, handler)
|
|
193
191
|
server.put(path, handler)
|
|
194
192
|
server.delete(path, handler)
|
|
195
|
-
server.listen(
|
|
193
|
+
server.listen(url, listenerInfo)
|
|
196
194
|
|
|
197
195
|
// Utilities (optional direct use)
|
|
198
196
|
import { crypto, compresor } from 'securequ';
|
|
@@ -224,7 +222,7 @@ new SecurequServer({
|
|
|
224
222
|
basepath: '/api',
|
|
225
223
|
clients: [{ origin, secret }],
|
|
226
224
|
upload?: { maxFilesize?, checkFileType?, chunk(), complete(), failed? },
|
|
227
|
-
accept?: (info) => boolean | Promise<boolean>
|
|
225
|
+
accept?: (info: HandlerInfo, metadata?: Metadata) => boolean | Promise<boolean>
|
|
228
226
|
});
|
|
229
227
|
|
|
230
228
|
// Client
|
package/server/Base.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Router from './Router.js';
|
|
2
|
-
import { SecurequServerConfig, UploadFileMeta, HandlerInfo,
|
|
2
|
+
import { SecurequServerConfig, UploadFileMeta, HandlerInfo, Metadata } from './types.js';
|
|
3
3
|
|
|
4
4
|
declare class SecurequServerBase extends Router {
|
|
5
5
|
protected config: SecurequServerConfig;
|
|
@@ -8,6 +8,7 @@ declare class SecurequServerBase extends Router {
|
|
|
8
8
|
protected uploadMeta: Map<string, UploadFileMeta & {
|
|
9
9
|
expire: number;
|
|
10
10
|
}>;
|
|
11
|
+
readonly CONTENT_TYPE = "application/octet-stream";
|
|
11
12
|
constructor(config: SecurequServerConfig);
|
|
12
13
|
protected getSecret(): Promise<string>;
|
|
13
14
|
protected clientInfo(path: string, origin: string): Promise<{
|
|
@@ -17,9 +18,9 @@ declare class SecurequServerBase extends Router {
|
|
|
17
18
|
searchParams: {
|
|
18
19
|
[key: string]: any;
|
|
19
20
|
};
|
|
20
|
-
}>;
|
|
21
|
+
} | null>;
|
|
21
22
|
protected isValidSigneture(signeture: string | undefined, hash: string): Promise<void>;
|
|
22
|
-
handleRequest(info: HandlerInfo,
|
|
23
|
+
handleRequest(info: HandlerInfo, metadata?: Metadata): Promise<void>;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
export { SecurequServerBase as default };
|
package/server/Base.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../include/crypto.js"),t=require("./Router.js");class s extends t.default{constructor(e){if(super(),this.secret=null,this.clients=new Map,this.uploadMeta=new Map,!e.basepath)throw new Error("Basepath is required");if(!e.clients||0===Object.keys(e.clients).length)throw new Error("Atleast one client is required");e.basepath.startsWith("/")||(e.basepath=`/${e.basepath}`),e.basepath.endsWith("/")&&(e.basepath=e.basepath.substring(0,e.basepath.length-1)),e.
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../include/crypto.js"),t=require("./Router.js");class s extends t.default{constructor(e){if(super(),this.secret=null,this.clients=new Map,this.uploadMeta=new Map,this.CONTENT_TYPE="application/octet-stream",!e.basepath)throw new Error("Basepath is required");if(!e.clients||0===Object.keys(e.clients).length)throw new Error("Atleast one client is required");e.basepath.startsWith("/")||(e.basepath=`/${e.basepath}`),e.basepath.endsWith("/")&&(e.basepath=e.basepath.substring(0,e.basepath.length-1)),e.file&&(e.file.maxFilesize=e.file.maxFilesize||51200,e.file.checkFileType=e.file.checkFileType||!0),e.mode=["production","development"].includes(e.mode||"")?e.mode:"production",this.config=e;for(let e of this.config.clients)this.clients.set(e.origin,e.secret)}async getSecret(){return this.secret||(this.secret=await e.default.hash(Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15))),this.secret}async clientInfo(t,s){const i="/"!==t&&"development"===this.config.mode;let a=t.split("?");const n=(t=(t=(t=(t=a[0]).replace(this.config.basepath+"/","")).endsWith("/")?t.substring(0,t.length-1):t).startsWith("/")?t.substring(1):t).split("/"),r=n.shift();let c=this.clients.get(s);if(c||(c=this.clients.get("*")),!(null==r?void 0:r.length)||!c)return null;let o=c.substring(0,r.length),h={};return a.length>1&&(h=i?Object.fromEntries(new URLSearchParams(decodeURIComponent(a[1]))):await e.default.decrypt(decodeURIComponent(a[1]),o)),{path:"/"+n.join("/"),secret:o,hash:r,searchParams:h}}async isValidSigneture(t,s){const i=await this.getSecret();if(this.secret&&t){let a=await e.default.decrypt(t,i),n=a.hash===s,r=a.expire>Date.now();if(!n)throw new Response("Invalid Signeture",{status:403});if(!r)throw new Response("Signeture expired",{status:403})}}async handleRequest(e,t){if(this.config.accept){if(!await this.config.accept(e,t))throw new Response("Request not accepted",{status:403})}const{path:s,method:i}=e;let a=Object.values(this.routes[i]);for(let{test:i,handler:n}of a){const a=i(s);a&&await n(Object.assign(Object.assign({},e),{params:a.params}),t)}}}exports.default=s;//# sourceMappingURL=Base.js.map
|
package/server/Base.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Base.js","sources":["../../src/server/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\r\nimport Router from \"./Router\";\r\nimport { HandlerInfo, SecurequServerConfig, ServerClientSecret, ServerClientOrigin, UploadFileMeta,
|
|
1
|
+
{"version":3,"file":"Base.js","sources":["../../src/server/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\r\nimport Router from \"./Router\";\r\nimport { HandlerInfo, SecurequServerConfig, ServerClientSecret, ServerClientOrigin, UploadFileMeta, Metadata } from \"./types\";\r\n\r\nclass SecurequServerBase extends Router {\r\n protected config: SecurequServerConfig;\r\n protected secret: string | null = null\r\n protected clients = new Map<ServerClientOrigin, ServerClientSecret>();\r\n protected uploadMeta = new Map<string, UploadFileMeta & { expire: number }>();\r\n readonly CONTENT_TYPE = \"application/octet-stream\";\r\n\r\n constructor(config: SecurequServerConfig) {\r\n super()\r\n if (!config.basepath) throw new Error(\"Basepath is required\");\r\n if (!config.clients || Object.keys(config.clients).length === 0) throw new Error(\"Atleast one client is required\");\r\n if (!config.basepath.startsWith(\"/\")) config.basepath = `/${config.basepath}`;\r\n if (config.basepath.endsWith(\"/\")) config.basepath = config.basepath.substring(0, config.basepath.length - 1);\r\n if (config.file) {\r\n config.file.maxFilesize = config.file.maxFilesize || 50 * 1024 // 50MB default\r\n config.file.checkFileType = config.file.checkFileType || true\r\n }\r\n config.mode = [\"production\", 'development'].includes(config.mode || \"\") ? config.mode : \"production\"\r\n this.config = config\r\n for (let client of this.config.clients) {\r\n this.clients.set(client.origin, client.secret)\r\n }\r\n }\r\n\r\n protected async getSecret() {\r\n if (!this.secret) {\r\n this.secret = await crypto.hash(Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15))\r\n }\r\n return this.secret\r\n }\r\n\r\n protected async clientInfo(path: string, origin: string) {\r\n const isDev = path !== '/' && this.config.mode === 'development'\r\n let splitUrl = path.split(\"?\")\r\n path = splitUrl[0]\r\n path = path.replace(this.config.basepath + \"/\", \"\")\r\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\r\n path = path.startsWith('/') ? path.substring(1) : path\r\n\r\n const split = path.split(\"/\")\r\n const hash = split.shift()\r\n let client = this.clients.get(origin)\r\n if (!client) {\r\n client = this.clients.get(\"*\")\r\n }\r\n\r\n if (!hash?.length || !client) return null\r\n let secret = client.substring(0, hash.length as number);\r\n let searchParams: { [key: string]: any } = {}\r\n if (splitUrl.length > 1) {\r\n if (isDev) {\r\n searchParams = Object.fromEntries(new URLSearchParams(decodeURIComponent(splitUrl[1])))\r\n } else {\r\n searchParams = await crypto.decrypt(decodeURIComponent(splitUrl[1]), secret) as any\r\n }\r\n }\r\n return {\r\n path: \"/\" + split.join('/'),\r\n secret,\r\n hash,\r\n searchParams\r\n }\r\n }\r\n\r\n protected async isValidSigneture(signeture: string | undefined, hash: string) {\r\n const serverSecret = await this.getSecret()\r\n if (this.secret && signeture) {\r\n let info: any = await crypto.decrypt(signeture, serverSecret)\r\n let isHashValid = info.hash === hash\r\n let isNotExpired = info.expire > Date.now()\r\n if (!isHashValid) throw new Response(\"Invalid Signeture\", { status: 403 });\r\n if (!isNotExpired) throw new Response(\"Signeture expired\", { status: 403 });\r\n }\r\n }\r\n\r\n async handleRequest(info: HandlerInfo, metadata?: Metadata) {\r\n if (this.config.accept) {\r\n const is = await this.config.accept(info, metadata)\r\n if (!is) throw new Response(\"Request not accepted\", { status: 403 })\r\n }\r\n\r\n const { path, method } = info;\r\n let values: any = Object.values(this.routes[method]);\r\n for (let { test, handler } of values) {\r\n const match = test(path)\r\n if (match) {\r\n await handler({ ...info, params: match.params }, metadata)\r\n }\r\n }\r\n }\r\n\r\n}\r\n\r\nexport default SecurequServerBase;"],"names":["SecurequServerBase","Router","constructor","config","super","this","secret","clients","Map","uploadMeta","CONTENT_TYPE","basepath","Error","Object","keys","length","startsWith","endsWith","substring","file","maxFilesize","checkFileType","mode","includes","client","set","origin","getSecret","crypto","hash","Math","random","toString","clientInfo","path","isDev","splitUrl","split","replace","shift","get","searchParams","fromEntries","URLSearchParams","decodeURIComponent","decrypt","join","isValidSigneture","signeture","serverSecret","info","isHashValid","isNotExpired","expire","Date","now","Response","status","handleRequest","metadata","accept","method","values","routes","test","handler","match","assign","params","exports","default"],"mappings":"mIAIA,MAAMA,UAA2BC,EAAAA,QAO9B,WAAAC,CAAYC,GAET,GADAC,QANOC,KAAAC,OAAwB,KACxBD,KAAAE,QAAU,IAAIC,IACdH,KAAAI,WAAa,IAAID,IAClBH,KAAAK,aAAe,4BAIhBP,EAAOQ,SAAU,MAAM,IAAIC,MAAM,wBACtC,IAAKT,EAAOI,SAAkD,IAAvCM,OAAOC,KAAKX,EAAOI,SAASQ,OAAc,MAAM,IAAIH,MAAM,kCAC5ET,EAAOQ,SAASK,WAAW,OAAMb,EAAOQ,SAAW,IAAIR,EAAOQ,YAC/DR,EAAOQ,SAASM,SAAS,OAAMd,EAAOQ,SAAWR,EAAOQ,SAASO,UAAU,EAAGf,EAAOQ,SAASI,OAAS,IACvGZ,EAAOgB,OACRhB,EAAOgB,KAAKC,YAAcjB,EAAOgB,KAAKC,aAAe,MACrDjB,EAAOgB,KAAKE,cAAgBlB,EAAOgB,KAAKE,gBAAiB,GAE5DlB,EAAOmB,KAAO,CAAC,aAAc,eAAeC,SAASpB,EAAOmB,MAAQ,IAAMnB,EAAOmB,KAAO,aACxFjB,KAAKF,OAASA,EACd,IAAK,IAAIqB,KAAUnB,KAAKF,OAAOI,QAC5BF,KAAKE,QAAQkB,IAAID,EAAOE,OAAQF,EAAOlB,OAE7C,CAEU,eAAMqB,GAIb,OAHKtB,KAAKC,SACPD,KAAKC,aAAesB,EAAAA,QAAOC,KAAKC,KAAKC,SAASC,SAAS,IAAId,UAAU,EAAG,IAAMY,KAAKC,SAASC,SAAS,IAAId,UAAU,EAAG,MAElHb,KAAKC,MACf,CAEU,gBAAM2B,CAAWC,EAAcR,GACtC,MAAMS,EAAiB,MAATD,GAAqC,gBAArB7B,KAAKF,OAAOmB,KAC1C,IAAIc,EAAWF,EAAKG,MAAM,KAM1B,MAAMA,GAFNH,GADAA,GADAA,GADAA,EAAOE,EAAS,IACJE,QAAQjC,KAAKF,OAAOQ,SAAW,IAAK,KACpCM,SAAS,KAAOiB,EAAKhB,UAAU,EAAGgB,EAAKnB,OAAS,GAAKmB,GACrDlB,WAAW,KAAOkB,EAAKhB,UAAU,GAAKgB,GAE/BG,MAAM,KACnBR,EAAOQ,EAAME,QACnB,IAAIf,EAASnB,KAAKE,QAAQiC,IAAId,GAK9B,GAJKF,IACFA,EAASnB,KAAKE,QAAQiC,IAAI,QAGxBX,aAAI,EAAJA,EAAMd,UAAWS,EAAQ,OAAO,KACrC,IAAIlB,EAASkB,EAAON,UAAU,EAAGW,EAAKd,QAClC0B,EAAuC,CAAA,EAQ3C,OAPIL,EAASrB,OAAS,IAEhB0B,EADCN,EACctB,OAAO6B,YAAY,IAAIC,gBAAgBC,mBAAmBR,EAAS,YAE7DR,EAAAA,QAAOiB,QAAQD,mBAAmBR,EAAS,IAAK9B,IAGpE,CACJ4B,KAAM,IAAMG,EAAMS,KAAK,KACvBxC,SACAuB,OACAY,eAEN,CAEU,sBAAMM,CAAiBC,EAA+BnB,GAC7D,MAAMoB,QAAqB5C,KAAKsB,YAChC,GAAItB,KAAKC,QAAU0C,EAAW,CAC3B,IAAIE,QAAkBtB,EAAAA,QAAOiB,QAAQG,EAAWC,GAC5CE,EAAcD,EAAKrB,OAASA,EAC5BuB,EAAeF,EAAKG,OAASC,KAAKC,MACtC,IAAKJ,EAAa,MAAM,IAAIK,SAAS,oBAAqB,CAAEC,OAAQ,MACpE,IAAKL,EAAc,MAAM,IAAII,SAAS,oBAAqB,CAAEC,OAAQ,KACvE,CACJ,CAEA,mBAAMC,CAAcR,EAAmBS,GACpC,GAAItD,KAAKF,OAAOyD,OAAQ,CAErB,UADiBvD,KAAKF,OAAOyD,OAAOV,EAAMS,GACjC,MAAM,IAAIH,SAAS,uBAAwB,CAAEC,OAAQ,KAChE,CAED,MAAMvB,KAAEA,EAAI2B,OAAEA,GAAWX,EACzB,IAAIY,EAAcjD,OAAOiD,OAAOzD,KAAK0D,OAAOF,IAC5C,IAAK,IAAIG,KAAEA,EAAIC,QAAEA,KAAaH,EAAQ,CACnC,MAAMI,EAAQF,EAAK9B,GACfgC,SACKD,EAAOpD,OAAAsD,OAAAtD,OAAAsD,OAAA,CAAA,EAAMjB,GAAI,CAAEkB,OAAQF,EAAME,SAAUT,EAEtD,CACJ,EAEFU,QAAAC,QAAAtE"}
|
package/server/Base.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import e from"../include/crypto.mjs";import t from"./Router.mjs";class s extends t{constructor(e){if(super(),this.secret=null,this.clients=new Map,this.uploadMeta=new Map,this.CONTENT_TYPE="application/octet-stream",!e.basepath)throw new Error("Basepath is required");if(!e.clients||0===Object.keys(e.clients).length)throw new Error("Atleast one client is required");e.basepath.startsWith("/")||(e.basepath=`/${e.basepath}`),e.basepath.endsWith("/")&&(e.basepath=e.basepath.substring(0,e.basepath.length-1)),e.file&&(e.file.maxFilesize=e.file.maxFilesize||51200,e.file.checkFileType=e.file.checkFileType||!0),e.mode=["production","development"].includes(e.mode||"")?e.mode:"production",this.config=e;for(let e of this.config.clients)this.clients.set(e.origin,e.secret)}async getSecret(){return this.secret||(this.secret=await e.hash(Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15))),this.secret}async clientInfo(t,s){const i="/"!==t&&"development"===this.config.mode;let n=t.split("?");const a=(t=(t=(t=(t=n[0]).replace(this.config.basepath+"/","")).endsWith("/")?t.substring(0,t.length-1):t).startsWith("/")?t.substring(1):t).split("/"),r=a.shift();let o=this.clients.get(s);if(o||(o=this.clients.get("*")),!(null==r?void 0:r.length)||!o)return null;let c=o.substring(0,r.length),h={};return n.length>1&&(h=i?Object.fromEntries(new URLSearchParams(decodeURIComponent(n[1]))):await e.decrypt(decodeURIComponent(n[1]),c)),{path:"/"+a.join("/"),secret:c,hash:r,searchParams:h}}async isValidSigneture(t,s){const i=await this.getSecret();if(this.secret&&t){let n=await e.decrypt(t,i),a=n.hash===s,r=n.expire>Date.now();if(!a)throw new Response("Invalid Signeture",{status:403});if(!r)throw new Response("Signeture expired",{status:403})}}async handleRequest(e,t){if(this.config.accept){if(!await this.config.accept(e,t))throw new Response("Request not accepted",{status:403})}const{path:s,method:i}=e;let n=Object.values(this.routes[i]);for(let{test:i,handler:a}of n){const n=i(s);n&&await a(Object.assign(Object.assign({},e),{params:n.params}),t)}}}export{s as default};//# sourceMappingURL=Base.mjs.map
|
package/server/Base.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Base.mjs","sources":["../../src/server/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\r\nimport Router from \"./Router\";\r\nimport { HandlerInfo, SecurequServerConfig, ServerClientSecret, ServerClientOrigin, UploadFileMeta,
|
|
1
|
+
{"version":3,"file":"Base.mjs","sources":["../../src/server/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\r\nimport Router from \"./Router\";\r\nimport { HandlerInfo, SecurequServerConfig, ServerClientSecret, ServerClientOrigin, UploadFileMeta, Metadata } from \"./types\";\r\n\r\nclass SecurequServerBase extends Router {\r\n protected config: SecurequServerConfig;\r\n protected secret: string | null = null\r\n protected clients = new Map<ServerClientOrigin, ServerClientSecret>();\r\n protected uploadMeta = new Map<string, UploadFileMeta & { expire: number }>();\r\n readonly CONTENT_TYPE = \"application/octet-stream\";\r\n\r\n constructor(config: SecurequServerConfig) {\r\n super()\r\n if (!config.basepath) throw new Error(\"Basepath is required\");\r\n if (!config.clients || Object.keys(config.clients).length === 0) throw new Error(\"Atleast one client is required\");\r\n if (!config.basepath.startsWith(\"/\")) config.basepath = `/${config.basepath}`;\r\n if (config.basepath.endsWith(\"/\")) config.basepath = config.basepath.substring(0, config.basepath.length - 1);\r\n if (config.file) {\r\n config.file.maxFilesize = config.file.maxFilesize || 50 * 1024 // 50MB default\r\n config.file.checkFileType = config.file.checkFileType || true\r\n }\r\n config.mode = [\"production\", 'development'].includes(config.mode || \"\") ? config.mode : \"production\"\r\n this.config = config\r\n for (let client of this.config.clients) {\r\n this.clients.set(client.origin, client.secret)\r\n }\r\n }\r\n\r\n protected async getSecret() {\r\n if (!this.secret) {\r\n this.secret = await crypto.hash(Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15))\r\n }\r\n return this.secret\r\n }\r\n\r\n protected async clientInfo(path: string, origin: string) {\r\n const isDev = path !== '/' && this.config.mode === 'development'\r\n let splitUrl = path.split(\"?\")\r\n path = splitUrl[0]\r\n path = path.replace(this.config.basepath + \"/\", \"\")\r\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\r\n path = path.startsWith('/') ? path.substring(1) : path\r\n\r\n const split = path.split(\"/\")\r\n const hash = split.shift()\r\n let client = this.clients.get(origin)\r\n if (!client) {\r\n client = this.clients.get(\"*\")\r\n }\r\n\r\n if (!hash?.length || !client) return null\r\n let secret = client.substring(0, hash.length as number);\r\n let searchParams: { [key: string]: any } = {}\r\n if (splitUrl.length > 1) {\r\n if (isDev) {\r\n searchParams = Object.fromEntries(new URLSearchParams(decodeURIComponent(splitUrl[1])))\r\n } else {\r\n searchParams = await crypto.decrypt(decodeURIComponent(splitUrl[1]), secret) as any\r\n }\r\n }\r\n return {\r\n path: \"/\" + split.join('/'),\r\n secret,\r\n hash,\r\n searchParams\r\n }\r\n }\r\n\r\n protected async isValidSigneture(signeture: string | undefined, hash: string) {\r\n const serverSecret = await this.getSecret()\r\n if (this.secret && signeture) {\r\n let info: any = await crypto.decrypt(signeture, serverSecret)\r\n let isHashValid = info.hash === hash\r\n let isNotExpired = info.expire > Date.now()\r\n if (!isHashValid) throw new Response(\"Invalid Signeture\", { status: 403 });\r\n if (!isNotExpired) throw new Response(\"Signeture expired\", { status: 403 });\r\n }\r\n }\r\n\r\n async handleRequest(info: HandlerInfo, metadata?: Metadata) {\r\n if (this.config.accept) {\r\n const is = await this.config.accept(info, metadata)\r\n if (!is) throw new Response(\"Request not accepted\", { status: 403 })\r\n }\r\n\r\n const { path, method } = info;\r\n let values: any = Object.values(this.routes[method]);\r\n for (let { test, handler } of values) {\r\n const match = test(path)\r\n if (match) {\r\n await handler({ ...info, params: match.params }, metadata)\r\n }\r\n }\r\n }\r\n\r\n}\r\n\r\nexport default SecurequServerBase;"],"names":["SecurequServerBase","Router","constructor","config","super","this","secret","clients","Map","uploadMeta","CONTENT_TYPE","basepath","Error","Object","keys","length","startsWith","endsWith","substring","file","maxFilesize","checkFileType","mode","includes","client","set","origin","getSecret","crypto","hash","Math","random","toString","clientInfo","path","isDev","splitUrl","split","replace","shift","get","searchParams","fromEntries","URLSearchParams","decodeURIComponent","decrypt","join","isValidSigneture","signeture","serverSecret","info","isHashValid","isNotExpired","expire","Date","now","Response","status","handleRequest","metadata","accept","method","values","routes","test","handler","match","assign","params"],"mappings":"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"}
|
package/server/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UploadFileMeta, ListenerInfo, ServerResponse } from './types.js';
|
|
2
2
|
import SecurequServerBase from './Base.js';
|
|
3
3
|
|
|
4
4
|
declare class SecurequServer extends SecurequServerBase {
|
|
5
5
|
handshake(body: any, clientInfo: any): Promise<void>;
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
uploadFile(file: File, onProgress?: (p: number) => void): Promise<UploadFileMeta>;
|
|
7
|
+
deleteFile(fileId: string): Promise<void>;
|
|
8
|
+
listen(url: string, { body, headers, metadata }: ListenerInfo): Promise<ServerResponse>;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export { SecurequServer as default };
|
package/server/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../include/crypto.js"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("tslib"),t=require("../include/crypto.js"),i=require("./Base.js"),n=require("../include/FileScaner.js"),a=require("../include/File.js");class s extends i.default{async handshake(e,i){var n,a;const s=await t.default.decryptBuffer(e,i.secret),r=await this.getSecret();if(!s)throw new Error("Invalid handshake data");if(s.hash!==i.hash)throw new Error("Invalid handshake");if(s.secret!==i.secret)throw new Error("Invalid handshake secret");if(Date.now()-s.clientTime>3e4)throw new Error("Handshake expired");const o=new Date,l=new Date(s.clientTime).getTime()-o.getTime();throw{dev:"development"===this.config.mode,timeDiffarenc:l,maxFileSize:(null===(n=this.config.file)||void 0===n?void 0:n.maxFilesize)||null,checkFileType:(null===(a=this.config.file)||void 0===a?void 0:a.checkFileType)||!1,signeture:await t.default.encrypt({expire:Date.now()+3e4,hash:i.hash},r)}}async uploadFile(t,i){var s,r,o,l,c;if(!(null===(c=this.config.file)||void 0===c?void 0:c.upload))throw new Response("Upload not supported",{status:403});const d=await a.getFileId(t),u=this.config.file.chunkSize,h={fileId:d,name:t.name,size:t.size,type:t.type,totalChunks:a.totalChunks(t,u),chunkIndex:0,isFinish:!1};try{for(var f,w=!0,p=e.__asyncValues(a.chunkFile(t,u));!(s=(f=await p.next()).done);){l=f.value,w=!1;try{let{chunk:e,chunkIndex:t}=l;if(this.config.file.checkFileType&&0===t){if(!n.fileScaner(e))throw new Error("Unknown or unsupported file type")}if(h.chunkIndex=t,h.isFinish=t+1===h.totalChunks,await this.config.file.upload(e,h),i){i(Math.floor((t+1)/h.totalChunks*100))}}finally{w=!0}}}catch(e){r={error:e}}finally{try{w||s||!(o=p.return)||await o.call(p)}finally{if(r)throw r.error}}return h}async deleteFile(e){var t;if(!(null===(t=this.config.file)||void 0===t?void 0:t.delete))throw new Response("Delete not supported",{status:403});await this.config.file.delete(e)}async listen(e,{body:i,headers:a,metadata:s}){const r=a["x-signeture"]||"",o=a["x-origin"]||"",l=a["x-method"]||"POST";let c=await this.clientInfo(e,o);if(!c)return{status:403,content:"Client not allowed"};let d=c.path;const u="/"!==d&&"development"===this.config.mode;try{if("/"===d&&"POST"===l&&await this.handshake(i,c),"/"===d&&"GET"===l)throw new Response("Invalid method",{status:405});const e=await t.default.decrypt(r,c.secret);if(e.expire<Date.now())throw new Response("Request expired",{status:403});await this.isValidSigneture(e.signeture,c.hash);let a=null;if(i)if(u){const e=(new TextDecoder).decode(i);a=JSON.parse(e)}else a=await t.default.decryptBuffer(i,c.secret);if("/"===d){const e=this.config.file;if("PUT"===l){if(!(null==e?void 0:e.upload))throw new Response("Upload not supported",{status:403});const t=a.filemeta,i=a.chunk;if(0===t.chunkIndex&&e.checkFileType&&!n.fileScaner(i))throw new Error("Unknown or unsupported file type");throw await e.upload(i,t),{success:!0}}throw"DELETE"===l?(await this.deleteFile(a.fileId),{success:!0}):new Response("Invalid method",{status:405})}await this.handleRequest({method:l,path:d,body:a,searchParams:c.searchParams,params:{}},s)}catch(e){const i=e instanceof Error,n=e instanceof Response;let a=i?e.message:n?await e.text():e;return u?{status:i?404:(null==e?void 0:e.status)||200,content:JSON.stringify(a)}:{status:i?404:(null==e?void 0:e.status)||200,content:await t.default.encryptBuffer(a,c.secret)}}return u?{status:404,content:"Not found"}:{status:404,content:await t.default.encryptBuffer("Not found",c.secret)}}}exports.default=s;//# sourceMappingURL=index.js.map
|
package/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/server/index.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\r\nimport { ArgsInfo, ListenerInfo, ServerResponse } from \"./types\";\r\nimport SecurequServerBase from \"./Base\";\r\nimport fileScaner from \"../include/FileScaner\";\r\n\r\nclass SecurequServer extends SecurequServerBase {\r\n\r\n async handshake(body: any, clientInfo: any) {\r\n const data: any = await crypto.decryptBuffer(body, clientInfo.secret)\r\n const serverSecret = await this.getSecret()\r\n if (!data) throw new Error(\"Invalid handshake data\");\r\n if (data.hash !== clientInfo.hash) {\r\n throw new Error(\"Invalid handshake\");\r\n } else if (data.secret !== clientInfo.secret) {\r\n throw new Error(\"Invalid handshake secret\");\r\n } else if (Date.now() - data.clientTime > 30000) { // 30 seconds\r\n throw new Error(\"Handshake expired\");\r\n }\r\n\r\n const serverTime = new Date();\r\n const clientDate = new Date(data.clientTime);\r\n const offsetMs = clientDate.getTime() - serverTime.getTime();\r\n\r\n let info = {\r\n timeDiffarenc: offsetMs,\r\n maxFileSize: this.config.upload?.maxFilesize || null,\r\n dev: this.config.mode === 'development',\r\n checkFileType: this.config.upload?.checkFileType || false,\r\n signeture: await crypto.encrypt({\r\n expire: Date.now() + 30000, // 30 seconds\r\n hash: clientInfo.hash\r\n }, serverSecret)\r\n }\r\n throw info\r\n }\r\n\r\n async upload(body: any, clientInfo: any, signeture: string, args?: ArgsInfo) {\r\n const data: any = await crypto.decryptBuffer(body, clientInfo.secret)\r\n const decryptSigneture = await crypto.decrypt(signeture, clientInfo.secret) as any\r\n await this.isValidSigneture(decryptSigneture.signeture, clientInfo.hash)\r\n const upload = this.config.upload\r\n\r\n if (!upload?.chunk || !upload?.complete) {\r\n throw new Response(\"Upload not supported\", { status: 403 })\r\n }\r\n\r\n if (data?.type === 'failed') {\r\n const meta = this.uploadMeta.get(data.fileid)\r\n if (meta && upload.failed) {\r\n await upload.failed(meta, args)\r\n this.uploadMeta.delete(data.fileid)\r\n throw { success: true }\r\n } else {\r\n throw new Response(\"Invalid upload\", { status: 400 })\r\n }\r\n } else if (data.type === 'meta') {\r\n if (upload?.maxFilesize && data.filesize > upload.maxFilesize * 1024) {\r\n throw new Response(`File size exceeds the limit of ${upload.maxFilesize} KB`, { status: 413 })\r\n }\r\n this.uploadMeta.set(data.fileid, {\r\n ...data,\r\n expire: Date.now() + 3600000 // 1 hour\r\n })\r\n this.uploadMeta.forEach((meta, key) => {\r\n if (meta.expire < Date.now()) {\r\n this.uploadMeta.delete(key)\r\n }\r\n })\r\n\r\n throw data\r\n } else {\r\n const { chunk, fileId, chunkIndex } = data;\r\n const meta = this.uploadMeta.get(fileId)\r\n if (!meta) {\r\n throw new Response(\"Invalid upload meta\", { status: 400 })\r\n }\r\n if (upload.checkFileType && chunkIndex === 0) {\r\n let fileType = fileScaner(chunk);\r\n if (!fileType) {\r\n throw new Error(\"Unknown or unsupported file type\");\r\n }\r\n }\r\n\r\n if (this.config.upload?.maxFilesize && data.filesize > this.config.upload.maxFilesize * 1024) {\r\n throw new Response(`File size exceeds the limit of ${this.config.upload.maxFilesize / 1024} MB`, { status: 413 })\r\n }\r\n await upload.chunk(chunk, {\r\n filename: meta.filename,\r\n filesize: meta.filesize,\r\n filetype: meta.filetype,\r\n fileid: meta.fileid,\r\n totalChunks: meta.totalChunks,\r\n chunkIndex,\r\n }, args)\r\n if (chunkIndex + 1 === meta.totalChunks) {\r\n const filepath = await upload.complete(meta, args)\r\n this.uploadMeta.delete(fileId)\r\n throw filepath\r\n }\r\n throw data\r\n }\r\n }\r\n\r\n async listen({ path, body, method, origin, signeture }: ListenerInfo, args?: ArgsInfo): Promise<ServerResponse> {\r\n let clientInfo = await this.clientInfo(path, origin)\r\n path = clientInfo.path\r\n const isDev = path !== '/' && this.config.mode === 'development'\r\n try {\r\n if (path === '/') {\r\n if (!['POST', 'PUT'].includes(method)) throw new Response(\"Invalid method\", { status: 405 });\r\n method === \"POST\"\r\n ? await this.handshake(body, clientInfo)\r\n : await this.upload(body, clientInfo, signeture, args);\r\n }\r\n\r\n const decryptSigneture = await crypto.decrypt(signeture, clientInfo.secret) as any\r\n await this.isValidSigneture(decryptSigneture.signeture, clientInfo.hash)\r\n\r\n // if reques is expired\r\n if (decryptSigneture.expire < Date.now()) throw new Response(\"Request expired\", { status: 403 });\r\n let data: any = null\r\n if (body) {\r\n if (isDev) {\r\n const decoder = new TextDecoder();\r\n const text = decoder.decode(body);\r\n data = JSON.parse(text)\r\n } else {\r\n data = await crypto.decryptBuffer(body, clientInfo.secret)\r\n }\r\n }\r\n\r\n await this.handleRequest({\r\n method,\r\n path,\r\n body: data,\r\n searchParams: clientInfo.searchParams,\r\n params: {}\r\n }, args);\r\n } catch (info: any) {\r\n const isError = info instanceof Error\r\n const isResponse = info instanceof Response\r\n let content = isError ? info.message : (isResponse ? await info.text() : info);\r\n if (path === '/') {\r\n\r\n }\r\n if (isDev) {\r\n return {\r\n status: isError ? 404 : (info?.status || 200),\r\n content: JSON.stringify(content)\r\n };\r\n }\r\n return {\r\n status: isError ? 404 : (info?.status || 200),\r\n content: await crypto.encryptBuffer(content, clientInfo.secret)\r\n };\r\n }\r\n\r\n if (isDev) {\r\n return {\r\n status: 404,\r\n content: \"Not found\"\r\n };\r\n }\r\n\r\n return {\r\n status: 404,\r\n content: await crypto.encryptBuffer(\"Not found\", clientInfo.secret)\r\n };\r\n }\r\n\r\n}\r\n\r\nexport default SecurequServer;"],"names":["SecurequServer","SecurequServerBase","handshake","body","clientInfo","data","crypto","decryptBuffer","secret","serverSecret","this","getSecret","Error","hash","Date","now","clientTime","serverTime","timeDiffarenc","getTime","maxFileSize","_a","config","upload","maxFilesize","dev","mode","checkFileType","_b","signeture","encrypt","expire","args","decryptSigneture","decrypt","isValidSigneture","chunk","complete","Response","status","type","meta","uploadMeta","get","fileid","failed","delete","success","filesize","set","Object","assign","forEach","key","fileId","chunkIndex","fileScaner","filename","filetype","totalChunks","filepath","listen","path","method","origin","isDev","includes","text","TextDecoder","decode","JSON","parse","handleRequest","searchParams","params","info","isError","isResponse","content","message","stringify","encryptBuffer","exports","default"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/server/index.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\r\nimport { Metadata, ListenerInfo, ServerResponse, UploadFileMeta } from \"./types\";\r\nimport SecurequServerBase from \"./Base\";\r\nimport fileScaner from \"../include/FileScaner\";\r\nimport { HTTPMethods } from \"../client/types\";\r\nimport { chunkFile, getFileId, totalChunks } from \"../include/File\";\r\n\r\nclass SecurequServer extends SecurequServerBase {\r\n\r\n async handshake(body: any, clientInfo: any) {\r\n const data: any = await crypto.decryptBuffer(body, clientInfo.secret)\r\n const serverSecret = await this.getSecret()\r\n if (!data) throw new Error(\"Invalid handshake data\");\r\n if (data.hash !== clientInfo.hash) {\r\n throw new Error(\"Invalid handshake\");\r\n } else if (data.secret !== clientInfo.secret) {\r\n throw new Error(\"Invalid handshake secret\");\r\n } else if (Date.now() - data.clientTime > 30000) { // 30 seconds\r\n throw new Error(\"Handshake expired\");\r\n }\r\n\r\n const serverTime = new Date();\r\n const clientDate = new Date(data.clientTime);\r\n const offsetMs = clientDate.getTime() - serverTime.getTime();\r\n\r\n let info = {\r\n dev: this.config.mode === 'development',\r\n timeDiffarenc: offsetMs,\r\n maxFileSize: this.config.file?.maxFilesize || null,\r\n checkFileType: this.config.file?.checkFileType || false,\r\n signeture: await crypto.encrypt({\r\n expire: Date.now() + 30000, // 30 seconds\r\n hash: clientInfo.hash\r\n }, serverSecret)\r\n }\r\n throw info\r\n }\r\n\r\n async uploadFile(file: File, onProgress?: (p: number) => void): Promise<UploadFileMeta> {\r\n if (!this.config.file?.upload) throw new Response(\"Upload not supported\", { status: 403 });\r\n\r\n const fileId = await getFileId(file);\r\n const chunkSize = this.config.file.chunkSize\r\n const filemeta: UploadFileMeta = {\r\n fileId: fileId,\r\n name: file.name,\r\n size: file.size,\r\n type: file.type,\r\n totalChunks: totalChunks(file, chunkSize),\r\n chunkIndex: 0,\r\n isFinish: false\r\n }\r\n\r\n for await (let { chunk, chunkIndex } of chunkFile(file, chunkSize)) {\r\n if (this.config.file.checkFileType && chunkIndex === 0) {\r\n let fileType = fileScaner(chunk);\r\n if (!fileType) throw new Error(\"Unknown or unsupported file type\");\r\n }\r\n filemeta.chunkIndex = chunkIndex;\r\n filemeta.isFinish = chunkIndex + 1 === filemeta.totalChunks;\r\n await this.config.file.upload(chunk, filemeta);\r\n if (onProgress) {\r\n const progress = Math.floor(((chunkIndex + 1) / filemeta.totalChunks) * 100)\r\n onProgress(progress);\r\n }\r\n }\r\n return filemeta\r\n }\r\n\r\n async deleteFile(fileId: string): Promise<void> {\r\n if (!this.config.file?.delete) throw new Response(\"Delete not supported\", { status: 403 })\r\n await this.config.file.delete(fileId);\r\n }\r\n\r\n async listen(url: string, { body, headers, metadata }: ListenerInfo): Promise<ServerResponse> {\r\n\r\n const signeture = headers['x-signeture'] || '';\r\n const origin = headers['x-origin'] || '';\r\n const method: HTTPMethods = headers['x-method'] || 'POST' as any\r\n\r\n let clientInfo = await this.clientInfo(url, origin)\r\n if (!clientInfo) {\r\n return {\r\n status: 403,\r\n content: \"Client not allowed\"\r\n }\r\n }\r\n let path = clientInfo.path\r\n const isDev = path !== '/' && this.config.mode === 'development'\r\n try {\r\n if (path === '/' && method === \"POST\") {\r\n await this.handshake(body, clientInfo)\r\n }\r\n\r\n if (path === '/' && method === 'GET') throw new Response(\"Invalid method\", { status: 405 })\r\n\r\n const decryptSigneture = await crypto.decrypt(signeture, clientInfo.secret) as any\r\n if (decryptSigneture.expire < Date.now()) throw new Response(\"Request expired\", { status: 403 });\r\n\r\n await this.isValidSigneture(decryptSigneture.signeture, clientInfo.hash)\r\n\r\n let data: any = null\r\n if (body) {\r\n if (isDev) {\r\n const decoder = new TextDecoder();\r\n const text = decoder.decode(body);\r\n data = JSON.parse(text)\r\n } else {\r\n data = await crypto.decryptBuffer(body, clientInfo.secret)\r\n }\r\n }\r\n\r\n if (path === '/') {\r\n\r\n const fileConfig = this.config.file\r\n\r\n // handle file upload\r\n if (method === \"PUT\") {\r\n if (!fileConfig?.upload) throw new Response(\"Upload not supported\", { status: 403 })\r\n\r\n const filemeta: UploadFileMeta = data.filemeta\r\n const chunk: Uint8Array = data.chunk\r\n\r\n if (filemeta.chunkIndex === 0 && fileConfig.checkFileType && !fileScaner(chunk)) {\r\n throw new Error(\"Unknown or unsupported file type\");\r\n }\r\n\r\n await fileConfig.upload(chunk, filemeta)\r\n throw { success: true }\r\n } else if (method === \"DELETE\") {\r\n await this.deleteFile(data.fileId)\r\n throw { success: true }\r\n } else {\r\n throw new Response(\"Invalid method\", { status: 405 });\r\n }\r\n }\r\n\r\n await this.handleRequest({\r\n method,\r\n path,\r\n body: data,\r\n searchParams: clientInfo.searchParams,\r\n params: {}\r\n }, metadata);\r\n\r\n } catch (info: any) {\r\n const isError = info instanceof Error\r\n const isResponse = info instanceof Response\r\n let content = isError ? info.message : (isResponse ? await info.text() : info);\r\n if (isDev) {\r\n return {\r\n status: isError ? 404 : (info?.status || 200),\r\n content: JSON.stringify(content)\r\n };\r\n }\r\n return {\r\n status: isError ? 404 : (info?.status || 200),\r\n content: await crypto.encryptBuffer(content, clientInfo.secret)\r\n };\r\n }\r\n\r\n if (isDev) {\r\n return {\r\n status: 404,\r\n content: \"Not found\"\r\n };\r\n }\r\n\r\n return {\r\n status: 404,\r\n content: await crypto.encryptBuffer(\"Not found\", clientInfo.secret)\r\n };\r\n }\r\n\r\n}\r\n\r\nexport default SecurequServer;"],"names":["SecurequServer","SecurequServerBase","handshake","body","clientInfo","data","crypto","decryptBuffer","secret","serverSecret","this","getSecret","Error","hash","Date","now","clientTime","serverTime","offsetMs","getTime","dev","config","mode","timeDiffarenc","maxFileSize","_a","file","maxFilesize","checkFileType","_b","signeture","encrypt","expire","uploadFile","onProgress","_d","upload","Response","status","fileId","getFileId","chunkSize","filemeta","name","size","type","totalChunks","chunkIndex","isFinish","_g","_e","_f","__asyncValues","chunkFile","next","done","_c","value","chunk","fileScaner","Math","floor","deleteFile","delete","listen","url","headers","metadata","origin","method","content","path","isDev","decryptSigneture","decrypt","isValidSigneture","text","TextDecoder","decode","JSON","parse","fileConfig","success","handleRequest","searchParams","params","info","isError","isResponse","message","stringify","encryptBuffer","exports","default"],"mappings":"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"}
|
package/server/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"../include/crypto.mjs";import
|
|
1
|
+
import{__asyncValues as e}from"tslib";import t from"../include/crypto.mjs";import i from"./Base.mjs";import{fileScaner as n}from"../include/FileScaner.mjs";import{getFileId as s,totalChunks as a,chunkFile as o}from"../include/File.mjs";class r extends i{async handshake(e,i){var n,s;const a=await t.decryptBuffer(e,i.secret),o=await this.getSecret();if(!a)throw new Error("Invalid handshake data");if(a.hash!==i.hash)throw new Error("Invalid handshake");if(a.secret!==i.secret)throw new Error("Invalid handshake secret");if(Date.now()-a.clientTime>3e4)throw new Error("Handshake expired");const r=new Date,l=new Date(a.clientTime).getTime()-r.getTime();throw{dev:"development"===this.config.mode,timeDiffarenc:l,maxFileSize:(null===(n=this.config.file)||void 0===n?void 0:n.maxFilesize)||null,checkFileType:(null===(s=this.config.file)||void 0===s?void 0:s.checkFileType)||!1,signeture:await t.encrypt({expire:Date.now()+3e4,hash:i.hash},o)}}async uploadFile(t,i){var r,l,c,h,d;if(!(null===(d=this.config.file)||void 0===d?void 0:d.upload))throw new Response("Upload not supported",{status:403});const f=await s(t),u=this.config.file.chunkSize,p={fileId:f,name:t.name,size:t.size,type:t.type,totalChunks:a(t,u),chunkIndex:0,isFinish:!1};try{for(var w,m=!0,y=e(o(t,u));!(r=(w=await y.next()).done);){h=w.value,m=!1;try{let{chunk:e,chunkIndex:t}=h;if(this.config.file.checkFileType&&0===t){if(!n(e))throw new Error("Unknown or unsupported file type")}if(p.chunkIndex=t,p.isFinish=t+1===p.totalChunks,await this.config.file.upload(e,p),i){i(Math.floor((t+1)/p.totalChunks*100))}}finally{m=!0}}}catch(e){l={error:e}}finally{try{m||r||!(c=y.return)||await c.call(y)}finally{if(l)throw l.error}}return p}async deleteFile(e){var t;if(!(null===(t=this.config.file)||void 0===t?void 0:t.delete))throw new Response("Delete not supported",{status:403});await this.config.file.delete(e)}async listen(e,{body:i,headers:s,metadata:a}){const o=s["x-signeture"]||"",r=s["x-origin"]||"",l=s["x-method"]||"POST";let c=await this.clientInfo(e,r);if(!c)return{status:403,content:"Client not allowed"};let h=c.path;const d="/"!==h&&"development"===this.config.mode;try{if("/"===h&&"POST"===l&&await this.handshake(i,c),"/"===h&&"GET"===l)throw new Response("Invalid method",{status:405});const e=await t.decrypt(o,c.secret);if(e.expire<Date.now())throw new Response("Request expired",{status:403});await this.isValidSigneture(e.signeture,c.hash);let s=null;if(i)if(d){const e=(new TextDecoder).decode(i);s=JSON.parse(e)}else s=await t.decryptBuffer(i,c.secret);if("/"===h){const e=this.config.file;if("PUT"===l){if(!(null==e?void 0:e.upload))throw new Response("Upload not supported",{status:403});const t=s.filemeta,i=s.chunk;if(0===t.chunkIndex&&e.checkFileType&&!n(i))throw new Error("Unknown or unsupported file type");throw await e.upload(i,t),{success:!0}}throw"DELETE"===l?(await this.deleteFile(s.fileId),{success:!0}):new Response("Invalid method",{status:405})}await this.handleRequest({method:l,path:h,body:s,searchParams:c.searchParams,params:{}},a)}catch(e){const i=e instanceof Error,n=e instanceof Response;let s=i?e.message:n?await e.text():e;return d?{status:i?404:(null==e?void 0:e.status)||200,content:JSON.stringify(s)}:{status:i?404:(null==e?void 0:e.status)||200,content:await t.encryptBuffer(s,c.secret)}}return d?{status:404,content:"Not found"}:{status:404,content:await t.encryptBuffer("Not found",c.secret)}}}export{r as default};//# sourceMappingURL=index.mjs.map
|
package/server/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../../src/server/index.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\r\nimport { ArgsInfo, ListenerInfo, ServerResponse } from \"./types\";\r\nimport SecurequServerBase from \"./Base\";\r\nimport fileScaner from \"../include/FileScaner\";\r\n\r\nclass SecurequServer extends SecurequServerBase {\r\n\r\n async handshake(body: any, clientInfo: any) {\r\n const data: any = await crypto.decryptBuffer(body, clientInfo.secret)\r\n const serverSecret = await this.getSecret()\r\n if (!data) throw new Error(\"Invalid handshake data\");\r\n if (data.hash !== clientInfo.hash) {\r\n throw new Error(\"Invalid handshake\");\r\n } else if (data.secret !== clientInfo.secret) {\r\n throw new Error(\"Invalid handshake secret\");\r\n } else if (Date.now() - data.clientTime > 30000) { // 30 seconds\r\n throw new Error(\"Handshake expired\");\r\n }\r\n\r\n const serverTime = new Date();\r\n const clientDate = new Date(data.clientTime);\r\n const offsetMs = clientDate.getTime() - serverTime.getTime();\r\n\r\n let info = {\r\n timeDiffarenc: offsetMs,\r\n maxFileSize: this.config.upload?.maxFilesize || null,\r\n dev: this.config.mode === 'development',\r\n checkFileType: this.config.upload?.checkFileType || false,\r\n signeture: await crypto.encrypt({\r\n expire: Date.now() + 30000, // 30 seconds\r\n hash: clientInfo.hash\r\n }, serverSecret)\r\n }\r\n throw info\r\n }\r\n\r\n async upload(body: any, clientInfo: any, signeture: string, args?: ArgsInfo) {\r\n const data: any = await crypto.decryptBuffer(body, clientInfo.secret)\r\n const decryptSigneture = await crypto.decrypt(signeture, clientInfo.secret) as any\r\n await this.isValidSigneture(decryptSigneture.signeture, clientInfo.hash)\r\n const upload = this.config.upload\r\n\r\n if (!upload?.chunk || !upload?.complete) {\r\n throw new Response(\"Upload not supported\", { status: 403 })\r\n }\r\n\r\n if (data?.type === 'failed') {\r\n const meta = this.uploadMeta.get(data.fileid)\r\n if (meta && upload.failed) {\r\n await upload.failed(meta, args)\r\n this.uploadMeta.delete(data.fileid)\r\n throw { success: true }\r\n } else {\r\n throw new Response(\"Invalid upload\", { status: 400 })\r\n }\r\n } else if (data.type === 'meta') {\r\n if (upload?.maxFilesize && data.filesize > upload.maxFilesize * 1024) {\r\n throw new Response(`File size exceeds the limit of ${upload.maxFilesize} KB`, { status: 413 })\r\n }\r\n this.uploadMeta.set(data.fileid, {\r\n ...data,\r\n expire: Date.now() + 3600000 // 1 hour\r\n })\r\n this.uploadMeta.forEach((meta, key) => {\r\n if (meta.expire < Date.now()) {\r\n this.uploadMeta.delete(key)\r\n }\r\n })\r\n\r\n throw data\r\n } else {\r\n const { chunk, fileId, chunkIndex } = data;\r\n const meta = this.uploadMeta.get(fileId)\r\n if (!meta) {\r\n throw new Response(\"Invalid upload meta\", { status: 400 })\r\n }\r\n if (upload.checkFileType && chunkIndex === 0) {\r\n let fileType = fileScaner(chunk);\r\n if (!fileType) {\r\n throw new Error(\"Unknown or unsupported file type\");\r\n }\r\n }\r\n\r\n if (this.config.upload?.maxFilesize && data.filesize > this.config.upload.maxFilesize * 1024) {\r\n throw new Response(`File size exceeds the limit of ${this.config.upload.maxFilesize / 1024} MB`, { status: 413 })\r\n }\r\n await upload.chunk(chunk, {\r\n filename: meta.filename,\r\n filesize: meta.filesize,\r\n filetype: meta.filetype,\r\n fileid: meta.fileid,\r\n totalChunks: meta.totalChunks,\r\n chunkIndex,\r\n }, args)\r\n if (chunkIndex + 1 === meta.totalChunks) {\r\n const filepath = await upload.complete(meta, args)\r\n this.uploadMeta.delete(fileId)\r\n throw filepath\r\n }\r\n throw data\r\n }\r\n }\r\n\r\n async listen({ path, body, method, origin, signeture }: ListenerInfo, args?: ArgsInfo): Promise<ServerResponse> {\r\n let clientInfo = await this.clientInfo(path, origin)\r\n path = clientInfo.path\r\n const isDev = path !== '/' && this.config.mode === 'development'\r\n try {\r\n if (path === '/') {\r\n if (!['POST', 'PUT'].includes(method)) throw new Response(\"Invalid method\", { status: 405 });\r\n method === \"POST\"\r\n ? await this.handshake(body, clientInfo)\r\n : await this.upload(body, clientInfo, signeture, args);\r\n }\r\n\r\n const decryptSigneture = await crypto.decrypt(signeture, clientInfo.secret) as any\r\n await this.isValidSigneture(decryptSigneture.signeture, clientInfo.hash)\r\n\r\n // if reques is expired\r\n if (decryptSigneture.expire < Date.now()) throw new Response(\"Request expired\", { status: 403 });\r\n let data: any = null\r\n if (body) {\r\n if (isDev) {\r\n const decoder = new TextDecoder();\r\n const text = decoder.decode(body);\r\n data = JSON.parse(text)\r\n } else {\r\n data = await crypto.decryptBuffer(body, clientInfo.secret)\r\n }\r\n }\r\n\r\n await this.handleRequest({\r\n method,\r\n path,\r\n body: data,\r\n searchParams: clientInfo.searchParams,\r\n params: {}\r\n }, args);\r\n } catch (info: any) {\r\n const isError = info instanceof Error\r\n const isResponse = info instanceof Response\r\n let content = isError ? info.message : (isResponse ? await info.text() : info);\r\n if (path === '/') {\r\n\r\n }\r\n if (isDev) {\r\n return {\r\n status: isError ? 404 : (info?.status || 200),\r\n content: JSON.stringify(content)\r\n };\r\n }\r\n return {\r\n status: isError ? 404 : (info?.status || 200),\r\n content: await crypto.encryptBuffer(content, clientInfo.secret)\r\n };\r\n }\r\n\r\n if (isDev) {\r\n return {\r\n status: 404,\r\n content: \"Not found\"\r\n };\r\n }\r\n\r\n return {\r\n status: 404,\r\n content: await crypto.encryptBuffer(\"Not found\", clientInfo.secret)\r\n };\r\n }\r\n\r\n}\r\n\r\nexport default SecurequServer;"],"names":["SecurequServer","SecurequServerBase","handshake","body","clientInfo","data","crypto","decryptBuffer","secret","serverSecret","this","getSecret","Error","hash","Date","now","clientTime","serverTime","timeDiffarenc","getTime","maxFileSize","_a","config","upload","maxFilesize","dev","mode","checkFileType","_b","signeture","encrypt","expire","args","decryptSigneture","decrypt","isValidSigneture","chunk","complete","Response","status","type","meta","uploadMeta","get","fileid","failed","delete","success","filesize","set","Object","assign","forEach","key","fileId","chunkIndex","fileScaner","filename","filetype","totalChunks","filepath","listen","path","method","origin","isDev","includes","text","TextDecoder","decode","JSON","parse","handleRequest","searchParams","params","info","isError","isResponse","content","message","stringify","encryptBuffer"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../src/server/index.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\r\nimport { Metadata, ListenerInfo, ServerResponse, UploadFileMeta } from \"./types\";\r\nimport SecurequServerBase from \"./Base\";\r\nimport fileScaner from \"../include/FileScaner\";\r\nimport { HTTPMethods } from \"../client/types\";\r\nimport { chunkFile, getFileId, totalChunks } from \"../include/File\";\r\n\r\nclass SecurequServer extends SecurequServerBase {\r\n\r\n async handshake(body: any, clientInfo: any) {\r\n const data: any = await crypto.decryptBuffer(body, clientInfo.secret)\r\n const serverSecret = await this.getSecret()\r\n if (!data) throw new Error(\"Invalid handshake data\");\r\n if (data.hash !== clientInfo.hash) {\r\n throw new Error(\"Invalid handshake\");\r\n } else if (data.secret !== clientInfo.secret) {\r\n throw new Error(\"Invalid handshake secret\");\r\n } else if (Date.now() - data.clientTime > 30000) { // 30 seconds\r\n throw new Error(\"Handshake expired\");\r\n }\r\n\r\n const serverTime = new Date();\r\n const clientDate = new Date(data.clientTime);\r\n const offsetMs = clientDate.getTime() - serverTime.getTime();\r\n\r\n let info = {\r\n dev: this.config.mode === 'development',\r\n timeDiffarenc: offsetMs,\r\n maxFileSize: this.config.file?.maxFilesize || null,\r\n checkFileType: this.config.file?.checkFileType || false,\r\n signeture: await crypto.encrypt({\r\n expire: Date.now() + 30000, // 30 seconds\r\n hash: clientInfo.hash\r\n }, serverSecret)\r\n }\r\n throw info\r\n }\r\n\r\n async uploadFile(file: File, onProgress?: (p: number) => void): Promise<UploadFileMeta> {\r\n if (!this.config.file?.upload) throw new Response(\"Upload not supported\", { status: 403 });\r\n\r\n const fileId = await getFileId(file);\r\n const chunkSize = this.config.file.chunkSize\r\n const filemeta: UploadFileMeta = {\r\n fileId: fileId,\r\n name: file.name,\r\n size: file.size,\r\n type: file.type,\r\n totalChunks: totalChunks(file, chunkSize),\r\n chunkIndex: 0,\r\n isFinish: false\r\n }\r\n\r\n for await (let { chunk, chunkIndex } of chunkFile(file, chunkSize)) {\r\n if (this.config.file.checkFileType && chunkIndex === 0) {\r\n let fileType = fileScaner(chunk);\r\n if (!fileType) throw new Error(\"Unknown or unsupported file type\");\r\n }\r\n filemeta.chunkIndex = chunkIndex;\r\n filemeta.isFinish = chunkIndex + 1 === filemeta.totalChunks;\r\n await this.config.file.upload(chunk, filemeta);\r\n if (onProgress) {\r\n const progress = Math.floor(((chunkIndex + 1) / filemeta.totalChunks) * 100)\r\n onProgress(progress);\r\n }\r\n }\r\n return filemeta\r\n }\r\n\r\n async deleteFile(fileId: string): Promise<void> {\r\n if (!this.config.file?.delete) throw new Response(\"Delete not supported\", { status: 403 })\r\n await this.config.file.delete(fileId);\r\n }\r\n\r\n async listen(url: string, { body, headers, metadata }: ListenerInfo): Promise<ServerResponse> {\r\n\r\n const signeture = headers['x-signeture'] || '';\r\n const origin = headers['x-origin'] || '';\r\n const method: HTTPMethods = headers['x-method'] || 'POST' as any\r\n\r\n let clientInfo = await this.clientInfo(url, origin)\r\n if (!clientInfo) {\r\n return {\r\n status: 403,\r\n content: \"Client not allowed\"\r\n }\r\n }\r\n let path = clientInfo.path\r\n const isDev = path !== '/' && this.config.mode === 'development'\r\n try {\r\n if (path === '/' && method === \"POST\") {\r\n await this.handshake(body, clientInfo)\r\n }\r\n\r\n if (path === '/' && method === 'GET') throw new Response(\"Invalid method\", { status: 405 })\r\n\r\n const decryptSigneture = await crypto.decrypt(signeture, clientInfo.secret) as any\r\n if (decryptSigneture.expire < Date.now()) throw new Response(\"Request expired\", { status: 403 });\r\n\r\n await this.isValidSigneture(decryptSigneture.signeture, clientInfo.hash)\r\n\r\n let data: any = null\r\n if (body) {\r\n if (isDev) {\r\n const decoder = new TextDecoder();\r\n const text = decoder.decode(body);\r\n data = JSON.parse(text)\r\n } else {\r\n data = await crypto.decryptBuffer(body, clientInfo.secret)\r\n }\r\n }\r\n\r\n if (path === '/') {\r\n\r\n const fileConfig = this.config.file\r\n\r\n // handle file upload\r\n if (method === \"PUT\") {\r\n if (!fileConfig?.upload) throw new Response(\"Upload not supported\", { status: 403 })\r\n\r\n const filemeta: UploadFileMeta = data.filemeta\r\n const chunk: Uint8Array = data.chunk\r\n\r\n if (filemeta.chunkIndex === 0 && fileConfig.checkFileType && !fileScaner(chunk)) {\r\n throw new Error(\"Unknown or unsupported file type\");\r\n }\r\n\r\n await fileConfig.upload(chunk, filemeta)\r\n throw { success: true }\r\n } else if (method === \"DELETE\") {\r\n await this.deleteFile(data.fileId)\r\n throw { success: true }\r\n } else {\r\n throw new Response(\"Invalid method\", { status: 405 });\r\n }\r\n }\r\n\r\n await this.handleRequest({\r\n method,\r\n path,\r\n body: data,\r\n searchParams: clientInfo.searchParams,\r\n params: {}\r\n }, metadata);\r\n\r\n } catch (info: any) {\r\n const isError = info instanceof Error\r\n const isResponse = info instanceof Response\r\n let content = isError ? info.message : (isResponse ? await info.text() : info);\r\n if (isDev) {\r\n return {\r\n status: isError ? 404 : (info?.status || 200),\r\n content: JSON.stringify(content)\r\n };\r\n }\r\n return {\r\n status: isError ? 404 : (info?.status || 200),\r\n content: await crypto.encryptBuffer(content, clientInfo.secret)\r\n };\r\n }\r\n\r\n if (isDev) {\r\n return {\r\n status: 404,\r\n content: \"Not found\"\r\n };\r\n }\r\n\r\n return {\r\n status: 404,\r\n content: await crypto.encryptBuffer(\"Not found\", clientInfo.secret)\r\n };\r\n }\r\n\r\n}\r\n\r\nexport default SecurequServer;"],"names":["SecurequServer","SecurequServerBase","handshake","body","clientInfo","data","crypto","decryptBuffer","secret","serverSecret","this","getSecret","Error","hash","Date","now","clientTime","serverTime","offsetMs","getTime","dev","config","mode","timeDiffarenc","maxFileSize","_a","file","maxFilesize","checkFileType","_b","signeture","encrypt","expire","uploadFile","onProgress","_d","upload","Response","status","fileId","getFileId","chunkSize","filemeta","name","size","type","totalChunks","chunkIndex","isFinish","_g","_e","_f","__asyncValues","chunkFile","next","done","_c","value","chunk","fileScaner","Math","floor","deleteFile","delete","listen","url","headers","metadata","origin","method","content","path","isDev","decryptSigneture","decrypt","isValidSigneture","text","TextDecoder","decode","JSON","parse","fileConfig","success","handleRequest","searchParams","params","info","isError","isResponse","message","stringify","encryptBuffer"],"mappings":"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"}
|
package/server/types.d.ts
CHANGED
|
@@ -16,36 +16,37 @@ type ServerClient = {
|
|
|
16
16
|
secret: ServerClientSecret;
|
|
17
17
|
};
|
|
18
18
|
type UploadFileMeta = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
fileId: string;
|
|
20
|
+
name: string;
|
|
21
|
+
size: number;
|
|
22
|
+
type: string;
|
|
23
23
|
chunkIndex: number;
|
|
24
24
|
totalChunks: number;
|
|
25
|
+
isFinish: boolean;
|
|
25
26
|
};
|
|
26
27
|
type UploadFilePath = string;
|
|
27
|
-
type
|
|
28
|
+
type Metadata = {
|
|
28
29
|
[key: string]: any;
|
|
29
30
|
};
|
|
30
31
|
type SecurequServerConfig = {
|
|
31
|
-
mode
|
|
32
|
+
mode?: "production" | "development";
|
|
32
33
|
basepath: string;
|
|
33
34
|
clients: ServerClient[];
|
|
34
|
-
|
|
35
|
+
file?: {
|
|
35
36
|
maxFilesize?: number;
|
|
36
37
|
checkFileType?: boolean;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
chunkSize?: number;
|
|
39
|
+
upload: (chunk: Uint8Array, filemeta: UploadFileMeta) => Promise<void>;
|
|
40
|
+
delete: (filename: string) => Promise<void>;
|
|
40
41
|
};
|
|
41
|
-
accept?: (info: HandlerInfo,
|
|
42
|
+
accept?: (info: HandlerInfo, metadata?: Metadata) => boolean | Promise<boolean>;
|
|
42
43
|
};
|
|
43
44
|
type ListenerInfo = {
|
|
44
|
-
signeture: string;
|
|
45
|
-
path: string;
|
|
46
45
|
body: any;
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
headers: {
|
|
47
|
+
[key: string]: string;
|
|
48
|
+
};
|
|
49
|
+
metadata?: Metadata;
|
|
49
50
|
};
|
|
50
51
|
type HandlerInfo = {
|
|
51
52
|
path: string;
|
|
@@ -62,7 +63,7 @@ type ServerResponse = {
|
|
|
62
63
|
content: Uint8Array | string;
|
|
63
64
|
status: number;
|
|
64
65
|
};
|
|
65
|
-
type HandlerFunction = (info: HandlerInfo,
|
|
66
|
+
type HandlerFunction = (info: HandlerInfo, metadata?: Metadata) => (any | void) | Promise<Partial<any> | void>;
|
|
66
67
|
type RouteFactory = {
|
|
67
68
|
[key in HTTPMethods]: {
|
|
68
69
|
[path: string]: {
|
|
@@ -74,4 +75,4 @@ type RouteFactory = {
|
|
|
74
75
|
};
|
|
75
76
|
};
|
|
76
77
|
|
|
77
|
-
export type {
|
|
78
|
+
export type { HandlerFunction, HandlerInfo, ListenerInfo, Metadata, RouteFactory, SecurequServerConfig, ServerClient, ServerClientInfo, ServerClientOrigin, ServerClientSecret, ServerResponse, UploadFileMeta, UploadFilePath };
|