diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..85e7c1d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/.idea/
diff --git a/console/src/routes/+layout.svelte b/console/src/routes/+layout.svelte
deleted file mode 100644
index 235b8ab..0000000
--- a/console/src/routes/+layout.svelte
+++ /dev/null
@@ -1,199 +0,0 @@
-
-
-{#if $auth?.token}
-
-
-{:else}
-
-
-
-
JavascriptDB Console
-
-
-
-
-
-
-
-
-
-
- Or continue with
-
-
-
-
-
-
-
-
-{/if}
-
diff --git a/console/src/services/jsdb.ts b/console/src/services/jsdb.ts
index 9a52b74..72ce73a 100644
--- a/console/src/services/jsdb.ts
+++ b/console/src/services/jsdb.ts
@@ -1,3 +1,3 @@
import {initApp} from "@jsdb/sdk";
-export const {auth, db} = await initApp({serverUrl: 'http://localhost:3001', connector: 'HTTP'})
\ No newline at end of file
+export const {auth, db} = await initApp({serverUrl: 'http://localhost:3001', connector: 'HTTP'})
diff --git a/sdk/package-lock.json b/sdk/package-lock.json
index 8c1b624..bcb41d9 100644
--- a/sdk/package-lock.json
+++ b/sdk/package-lock.json
@@ -1,16 +1,15 @@
{
"name": "@jsdb/sdk",
- "version": "0.0.42",
+ "version": "0.0.45",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@jsdb/sdk",
- "version": "0.0.42",
+ "version": "0.0.45",
"license": "MIT",
"dependencies": {
- "isomorphic-ws": "^4.0.1",
- "ws": "^8.5.0"
+ "@auth/core": "^0.9.0"
},
"devDependencies": {
"@size-limit/preset-small-lib": "^7.0.8",
@@ -22,7 +21,7 @@
"typescript": "^3.9.10"
},
"engines": {
- "node": ">=18"
+ "node": ">=20"
}
},
"node_modules/@ampproject/remapping": {
@@ -38,6 +37,27 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@auth/core": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.9.0.tgz",
+ "integrity": "sha512-W2WO0WCBg1T3P8+yjQPzurTQhPv6ecBYfJ2oE3uvXPAX5ZLWAMSjKFAIa9oLZy5pwrB+YehJZPnlIxVilhrVcg==",
+ "dependencies": {
+ "@panva/hkdf": "^1.0.4",
+ "cookie": "0.5.0",
+ "jose": "^4.11.1",
+ "oauth4webapi": "^2.0.6",
+ "preact": "10.11.3",
+ "preact-render-to-string": "5.2.3"
+ },
+ "peerDependencies": {
+ "nodemailer": "^6.8.0"
+ },
+ "peerDependenciesMeta": {
+ "nodemailer": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@babel/code-frame": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
@@ -2247,6 +2267,14 @@
"node": ">= 8"
}
},
+ "node_modules/@panva/hkdf": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.1.1.tgz",
+ "integrity": "sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -3923,6 +3951,14 @@
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
"dev": true
},
+ "node_modules/cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/copy-descriptor": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
@@ -6901,14 +6937,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/isomorphic-ws": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz",
- "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==",
- "peerDependencies": {
- "ws": "*"
- }
- },
"node_modules/isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@@ -7852,6 +7880,14 @@
"node": ">= 8.3"
}
},
+ "node_modules/jose": {
+ "version": "4.14.4",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz",
+ "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/jpjs": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/jpjs/-/jpjs-1.2.1.tgz",
@@ -8701,6 +8737,14 @@
"node": "*"
}
},
+ "node_modules/oauth4webapi": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-2.3.0.tgz",
+ "integrity": "sha512-JGkb5doGrwzVDuHwgrR4nHJayzN4h59VCed6EW8Tql6iHDfZIabCJvg6wtbn5q6pyB2hZruI3b77Nudvq7NmvA==",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -9227,6 +9271,31 @@
"node": ">=0.10.0"
}
},
+ "node_modules/preact": {
+ "version": "10.11.3",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.3.tgz",
+ "integrity": "sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ }
+ },
+ "node_modules/preact-render-to-string": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.3.tgz",
+ "integrity": "sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==",
+ "dependencies": {
+ "pretty-format": "^3.8.0"
+ },
+ "peerDependencies": {
+ "preact": ">=10"
+ }
+ },
+ "node_modules/preact-render-to-string/node_modules/pretty-format": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
+ "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="
+ },
"node_modules/prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
@@ -12236,26 +12305,6 @@
"mkdirp": "bin/cmd.js"
}
},
- "node_modules/ws": {
- "version": "8.11.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
- "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
- "engines": {
- "node": ">=10.0.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": "^5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
"node_modules/xml-name-validator": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
@@ -12345,6 +12394,19 @@
"@jridgewell/trace-mapping": "^0.3.9"
}
},
+ "@auth/core": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.9.0.tgz",
+ "integrity": "sha512-W2WO0WCBg1T3P8+yjQPzurTQhPv6ecBYfJ2oE3uvXPAX5ZLWAMSjKFAIa9oLZy5pwrB+YehJZPnlIxVilhrVcg==",
+ "requires": {
+ "@panva/hkdf": "^1.0.4",
+ "cookie": "0.5.0",
+ "jose": "^4.11.1",
+ "oauth4webapi": "^2.0.6",
+ "preact": "10.11.3",
+ "preact-render-to-string": "5.2.3"
+ }
+ },
"@babel/code-frame": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
@@ -13951,6 +14013,11 @@
"fastq": "^1.6.0"
}
},
+ "@panva/hkdf": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.1.1.tgz",
+ "integrity": "sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA=="
+ },
"@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -15240,6 +15307,11 @@
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
"dev": true
},
+ "cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
+ },
"copy-descriptor": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
@@ -17386,12 +17458,6 @@
"integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
"dev": true
},
- "isomorphic-ws": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz",
- "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==",
- "requires": {}
- },
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@@ -18169,6 +18235,11 @@
"supports-color": "^7.0.0"
}
},
+ "jose": {
+ "version": "4.14.4",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz",
+ "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g=="
+ },
"jpjs": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/jpjs/-/jpjs-1.2.1.tgz",
@@ -18852,6 +18923,11 @@
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
"dev": true
},
+ "oauth4webapi": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-2.3.0.tgz",
+ "integrity": "sha512-JGkb5doGrwzVDuHwgrR4nHJayzN4h59VCed6EW8Tql6iHDfZIabCJvg6wtbn5q6pyB2hZruI3b77Nudvq7NmvA=="
+ },
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -19240,6 +19316,26 @@
"integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==",
"dev": true
},
+ "preact": {
+ "version": "10.11.3",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.3.tgz",
+ "integrity": "sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg=="
+ },
+ "preact-render-to-string": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.3.tgz",
+ "integrity": "sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==",
+ "requires": {
+ "pretty-format": "^3.8.0"
+ },
+ "dependencies": {
+ "pretty-format": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
+ "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="
+ }
+ }
+ },
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
@@ -21626,12 +21722,6 @@
"typedarray-to-buffer": "^3.1.5"
}
},
- "ws": {
- "version": "8.11.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
- "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
- "requires": {}
- },
"xml-name-validator": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
diff --git a/sdk/package.json b/sdk/package.json
index b05b8d6..38fd1d5 100644
--- a/sdk/package.json
+++ b/sdk/package.json
@@ -54,7 +54,9 @@
"tslib": "^2.4.0",
"typescript": "^3.9.10"
},
- "dependencies": {},
+ "dependencies": {
+ "@auth/core": "^0.9.0"
+ },
"description": "Install ```shell npm i @jsdb/sdk ```",
"directories": {
"test": "test"
diff --git a/sdk/src/index.ts b/sdk/src/index.ts
index 18f2875..84abe76 100644
--- a/sdk/src/index.ts
+++ b/sdk/src/index.ts
@@ -1,8 +1,10 @@
+import {getSignInPopup} from './providerSignin'
type document = { id: string, [key: string]: any }
type fn = (v: any) => any
const regexpIsoDate = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*))(?:Z|(\+|-)([\d|:]*))?$/;
+const SECONDS_TIMEOUT_SIGNIN_WINDOW = 60;
export async function initApp(config: { serverUrl?: string, apiKey?: string, connector: 'HTTP' | 'LOCAL' | 'WS', opHandlers?: any } = {connector: 'HTTP'}) {
config = {...{connector: 'HTTP'}, ...config};
let baseUrl = '';
@@ -155,25 +157,74 @@ export async function initApp(config: { serverUrl?: string, apiKey?: string, con
}
}
- signOut = () => {
- delete localStorage.token;
- delete localStorage.userId;
- this.set({});
- };
+ signOut = () => {
+ delete localStorage.token;
+ delete localStorage.userId;
+ this.set({})
+ }
+ async signInWithProvider(provider: string) {
+ return new Promise((resolve, reject) => {
+ const width = 450, height = 550, left = (screen.width - width) / 2, top = (screen.height - height) / 2;
+ let params = `width=${width}, height=${height}, top=${top}, left=${left}, titlebar=no, location=yes`
+ let timeout = setTimeout(() => {
+ loginWindow.close();
+ reject({message:`signInWith timeout exceeded`})
+ }, SECONDS_TIMEOUT_SIGNIN_WINDOW*1000)
+ let loginWindow: any;
+ const url = new URL('/', baseUrl);
+ const uniqueWindowId = `authorizationJavascriptDatabase`;
+ const handleMessage = (e: MessageEvent)=> {
+ console.log('Message: ', e.data)
+ const {token, user} = e.data;
+ clearTimeout(timeout);
+ loginWindow.close();
+ window.removeEventListener('message', handleMessage)
+ resolve({token, user});
+ }
+ window.addEventListener("message", handleMessage , false);
+ loginWindow = window.open(url.toString(), uniqueWindowId, params)
+ loginWindow.document.write(getSignInPopup(baseUrl, provider));
+ })
+ }
+ async defaultSignIn() {
+ return new Promise((resolve, reject) => {
+ const width = 450, height = 550, left = (screen.width - width) / 2, top = (screen.height - height) / 2;
+ let params = `width=${width}, height=${height}, top=${top}, left=${left}, titlebar=no, location=yes`
+ let timeout = setTimeout(() => {
+ loginWindow.close();
+ reject({message:`signInWith timeout exceeded`});
+ }, SECONDS_TIMEOUT_SIGNIN_WINDOW*1000)
+ let loginWindow: any;
+ const url = new URL('/auth/signin', baseUrl);
+ const uniqueWindowId = `authorizationJavascriptDatabase`;
+ const handleMessage = (e: MessageEvent)=> {
+ const {token, user} = JSON.parse(e.data);
+ console.log('Message: ', e.data)
+ clearTimeout(timeout);
+ loginWindow.close();
+ window.removeEventListener('message', handleMessage)
+ resolve({token, user});
+ }
+ window.addEventListener("message", handleMessage , false);
+ loginWindow = window.open(url.toString(), uniqueWindowId, params)
+ })
+ }
signIn = async (credentials: { email: string, password: string }) => {
- try {
- const {token, userId} = await request('/auth/signin', {...credentials});
- this.set({token, userId});
- if (typeof process !== 'object') {
- localStorage.token = this.value.token;
- localStorage.userId = this.value.userId;
+ try {
+ location.href = baseUrl + '/auth/signin';
+ console.log(credentials)
+ // this.set({token, userId})
+ // if (typeof process !== 'object') {
+ // localStorage.token = this.value.token;
+ // localStorage.userId = this.value.userId;
+ // }
+ // return true;
+ } catch (e) {
+ console.error(e);
+ throw new Error(`Error logging in, verify email and password`);
}
- return true;
- } catch (e) {
- throw new Error(`Error logging in, verify email and password`);
- }
- };
+ }
createAccount = async (credentials: { email: string, password: string }) => {
try {
diff --git a/sdk/src/providerSignin.ts b/sdk/src/providerSignin.ts
new file mode 100644
index 0000000..cba5b2d
--- /dev/null
+++ b/sdk/src/providerSignin.ts
@@ -0,0 +1,38 @@
+export function getSignInPopup(baseUrl: string, provider: string) {
+ return `
+
+
+
+
+
+ `
+}
diff --git a/server/http/auth.js b/server/http/auth.js
index e69de29..cb0eaa5 100644
--- a/server/http/auth.js
+++ b/server/http/auth.js
@@ -0,0 +1,133 @@
+import {Auth} from '@auth/core';
+import GitHub from '@auth/core/providers/github';
+import {readReadableStream} from '../utils.js';
+import {decode} from '@auth/core/jwt';
+import {sdkDb} from './sdk.js';
+import jsdbAdapter from './jsdbAdapter.js';
+
+// Request https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API needed by Auth.js
+export async function AuthModule(request) {
+ const optionsEnvVar = {
+ // Configure one or more authentication providers
+ providers: [
+ GitHub({
+ clientId: '8a9219d06d63a95bf1af',
+ clientSecret: '746ce3dd62cfbd400289e7647063ecc907ffab17',
+ }),
+ ],
+ trustHost: true,
+ secret: process.env.JWT_SECRET,
+ cookies: {
+ csrfToken: {
+ name: 'next-auth.csrf-token',
+ options: {
+ httpOnly: true,
+ sameSite: 'none',
+ path: '/',
+ secure: true
+ }
+ },
+ pkceCodeVerifier: {
+ name: 'next-auth.pkce.code_verifier',
+ options: {
+ httpOnly: true,
+ sameSite: 'none',
+ path: '/',
+ secure: true
+ }
+ }
+ },
+ callbacks: {
+ async signIn(args) {
+ // async signIn({user, account, profile, email, credentials}) {
+ // console.log(`signIn callback`)
+ return true
+ },
+ // async redirect({ url, baseUrl }) {
+ async redirect(args) {
+ //console.log(`redirect callback: ${JSON.stringify(args)}`)
+ return null
+ //return baseUrl
+ },
+ // async session({session, user, token}) {
+ async session(args) {
+ //console.log(`session callback: ${JSON.stringify(args)}`)
+ return args.session
+ },
+ // async jwt({token, user, account, profile, isNewUser}) {
+ async jwt(args) {
+ console.log(`jwt callback: ${JSON.stringify(args)}`)
+ return args.token;
+ }
+ },
+ adapter: jsdbAdapter(sdkDb)
+ }
+ let headers = new Headers();
+ const url = new URL(request.url)
+ if (['auth', 'db', 'functions'].includes(url.pathname.split('/')[1])) {
+ headers.set('Access-Control-Allow-Methods', 'OPTIONS, POST, GET')
+ headers.set('Access-Control-Allow-Headers', '*')
+ headers.set('Access-Control-Allow-Credentials', true)
+ if (request.headers.get('origin')) {
+ headers.set('Access-Control-Allow-Origin', request.headers.get('origin'))
+ }
+ if (request.method === 'OPTIONS') {
+ return new Response(null, {headers, status: 204});
+ }
+ if(url.pathname.includes('auth/signin/')) {
+ const body = await readReadableStream(request.clone().body)
+ const searchParams = new URLSearchParams(body);
+ if(searchParams?.get('customProviderSignin') === 'true') {
+ const pathname = (new URL(request.url)).pathname
+ const clone = new Request(new URL(pathname, process.env.SERVER_URL) , request)
+ request = clone
+ console.log('here')
+ }
+ }
+ const auth = await Auth(request, optionsEnvVar);
+ headers.set('access-control-expose-headers', 'set-cookie')
+ // merge both auth and added headers
+ for (const headerName of auth.headers.keys()) {
+ const header = auth.headers.get(headerName);
+ headers.set(headerName, header)
+ if (headerName === 'set-cookie') {
+ console.log(header)
+ }
+ }
+ for (const headerName of headers.keys()) {
+ const header = headers.get(headerName);
+ auth.headers.set(headerName, header)
+ }
+ if(url.pathname.includes('auth/callback') ) {
+ headers.set('Content-type', 'text/html')
+ const codedSessionToken = headers.get('set-cookie')
+ ?.split(';')
+ ?.map(dirtyCookie => dirtyCookie.split(','))
+ ?.flat()
+ ?.filter(keyValue => keyValue.includes('next-auth.session-token'))?.[0]
+ ?.split('=')?.[1];
+ const decodedSessionToken = await decode({
+ token: codedSessionToken,
+ secret: process.env.JWT_SECRET,
+ })
+
+ const resp = `
+
+`
+ return new Response(resp, {headers, status: 200});
+ }
+ // comes from sdk and all redirections needs to be triggered manually from the sdk
+ let origin = request.headers.get('origin')
+ if(origin) origin = new URL(origin);
+ if (auth.status === 302 && origin && origin.href !== process.env.SERVER_URL) {
+ // custom provider signin
+ return new Response(auth.headers.get('location'), {headers, status: 200});
+ } else {
+ return auth
+ }
+ }
+ return null
+}
+
diff --git a/server/http/base.js b/server/http/base.js
index 93f69f2..eb6ab0a 100644
--- a/server/http/base.js
+++ b/server/http/base.js
@@ -19,4 +19,4 @@ export async function route(path, body, user, skipSecurityRules, skipTrigger) {
} else if (module === 'storage') {
return routeStorage(operation, body);
}
-}
\ No newline at end of file
+}
diff --git a/server/http/jsdbAdapter.js b/server/http/jsdbAdapter.js
new file mode 100644
index 0000000..7f8d15e
--- /dev/null
+++ b/server/http/jsdbAdapter.js
@@ -0,0 +1,49 @@
+export default function MyAdapter(dbSdk) {
+ return {
+ async createUser(user) {
+ console.log('here')
+ await dbSdk.set('test', user)
+ // dbSdk.set('hello', {test:true})
+ return
+ },
+ async getUser(id) {
+ return
+ },
+ async getUserByEmail(email) {
+ return
+ },
+ async getUserByAccount({ providerAccountId, provider }) {
+ return
+ },
+ async updateUser(user) {
+ return
+ },
+ async deleteUser(userId) {
+ return
+ },
+ async linkAccount(account) {
+ return
+ },
+ async unlinkAccount({ providerAccountId, provider }) {
+ return
+ },
+ async createSession({ sessionToken, userId, expires }) {
+ return
+ },
+ async getSessionAndUser(sessionToken) {
+ return
+ },
+ async updateSession({ sessionToken }) {
+ return
+ },
+ async deleteSession(sessionToken) {
+ return
+ },
+ async createVerificationToken({ identifier, expires, token }) {
+ return
+ },
+ async useVerificationToken({ identifier, token }) {
+ return
+ },
+ }
+}
diff --git a/server/http/sdk.js b/server/http/sdk.js
new file mode 100644
index 0000000..b3e8a41
--- /dev/null
+++ b/server/http/sdk.js
@@ -0,0 +1,6 @@
+import {initApp} from "@jsdb/sdk";
+export let sdkApp, sdkDb;
+export async function initSdk() {
+ sdkApp = await initApp({serverUrl: process.env.SERVER_URL, connector: 'HTTP'})
+ sdkDb = sdkApp.db;
+}
diff --git a/server/package.json b/server/package.json
index c75a36f..9db5425 100644
--- a/server/package.json
+++ b/server/package.json
@@ -11,6 +11,7 @@
"author": "jpcapdevila",
"license": "SSPL",
"dependencies": {
+ "@auth/core": "^0.9.0",
"@jsdb/sdk": "file:../sdk",
"acorn": "^8.7.1",
"aws4fetch": "^1.0.17",
diff --git a/server/runtimes/node/index.js b/server/runtimes/node/index.js
index af3da86..078f0d7 100644
--- a/server/runtimes/node/index.js
+++ b/server/runtimes/node/index.js
@@ -1,16 +1,69 @@
import * as http from 'http';
import {WebSocketServer} from 'ws';
import {route} from '../../http/base.js';
-import {parseData, readStreamToPromise} from '../../utils.js';
+import {parseData, readReadableStream, readStreamToPromise} from '../../utils.js';
import jwt from 'jsonwebtoken';
import {getEventStore} from '../../ws/ws.js';
+import {AuthModule} from '../../http/auth.js';
+import {initSdk} from '../../http/sdk.js';
+
const wsServer = new WebSocketServer({noServer: true});
-const hostname = '0.0.0.0';
+const hostname = 'localhost'
const port = process.env.PORT || 3001;
+async function getBody(request) {
+ return new Promise((resolve) => {
+ const bodyParts = [];
+ let body;
+ request.on('data', (chunk) => {
+ bodyParts.push(chunk);
+ }).on('end', () => {
+ body = Buffer.concat(bodyParts).toString();
+ resolve(body)
+ });
+ });
+}
+async function convertIncomingMessageToRequest(req){
+ const headers = new Headers();
+ for (var key in req.headers) {
+ if (req.headers[key]) headers.append(key, req.headers[key]);
+ }
+ const body = req.method === 'POST' ? await getBody(req) : null;
+ // TODO remove hardcoded http
+ const baseUrl = process.env.SERVER_URL
+ console.log((new URL(req.url, baseUrl)).pathname)
+ const reqObj = {
+ ...req,
+ body,
+ headers,
+ }
+ let request = new Request(new URL(req.url, baseUrl), reqObj)
+ return request
+}
+async function convertResponseToServerResponse(response, serverResponse) {
+ const headers = {};
+ for (const headerName of response.headers.keys()) {
+ const header = response.headers.get(headerName);
+ headers[headerName] = header
+ }
+ serverResponse.writeHead(response.status, headers)
+ if(response.body) {
+ const body = await readReadableStream(response.body)
+ serverResponse.write(body)
+ }
+}
+
const server = http.createServer(async (req, res) => {
+ const request = await convertIncomingMessageToRequest(req)
+ const authResp = await AuthModule(request);
+ if(authResp) {
+ await convertResponseToServerResponse(authResp, res);
+ // Todo, remove this return and see if the user is auth or not
+ return res.end()
+ }
+
if (req.method === 'POST') {
const bodyString = await readStreamToPromise(req);
const body = parseData(bodyString);
@@ -25,10 +78,13 @@ const server = http.createServer(async (req, res) => {
res.end(JSON.stringify(result ?? null));
}
}
+ res.end();
});
-server.listen(port, hostname, () => {
+server.listen(port, hostname, async () => {
+ await initSdk()
console.log(`Server running at http://${hostname}:${port}/`);
+
});
server.on('upgrade', (request, socket, head) => {
@@ -78,4 +134,4 @@ wsServer.on('connection', socket => {
}
}
});
-});
\ No newline at end of file
+});
diff --git a/server/utils.js b/server/utils.js
index 34d7ca7..dd369ab 100644
--- a/server/utils.js
+++ b/server/utils.js
@@ -1,3 +1,5 @@
+import { Buffer } from 'node:buffer';
+
export function readStreamToPromise(stream) {
return new Promise((resolve, reject) => {
const chunks = [];
@@ -17,4 +19,11 @@ export function parseData(dataString) {
return value;
}
});
-}
\ No newline at end of file
+}
+export async function readReadableStream(readableStream) {
+ const chunks = [];
+ for await (const chunk of readableStream) {
+ chunks.push(Buffer.from(chunk));
+ }
+ return Buffer.concat(chunks).toString("utf-8");
+}