-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a local test environment with TLS and domain names.
- Loading branch information
1 parent
8ae649b
commit 5097865
Showing
20 changed files
with
3,497 additions
and
957 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
node_modules | ||
dist | ||
lib | ||
lib | ||
ca |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { createCA, createCert } from 'mkcert'; | ||
import { devDomains } from './localtest/siteDetails'; | ||
import fs from 'node:fs/promises'; | ||
|
||
const domains = devDomains; | ||
|
||
const caFolder = './ca/'; | ||
const caFile = `${caFolder}ca.crt`; | ||
const caKey = `${caFolder}ca.key`; | ||
const certFile = `${caFolder}cert.crt`; | ||
const certKey = `${caFolder}cert.key`; | ||
|
||
const overwriteFileOptions = { | ||
flag: 'w', | ||
}; | ||
const failIfExistsFileOptions = { | ||
flag: 'wx', | ||
}; | ||
|
||
const fileExists = async (path) => !!(await fs.stat(path).catch((e) => false)); | ||
const getOrCreateCA = async () => { | ||
if (await fileExists(caFile)) { | ||
console.log('Found existing CA, loading...'); | ||
return { | ||
cert: await fs.readFile(caFile, { encoding: 'utf8' }), | ||
key: await fs.readFile(caKey, { encoding: 'utf8' }), | ||
}; | ||
} else { | ||
console.log('Creating new CA...'); | ||
const ca = await createCA({ | ||
organization: 'UID2 local dev CA', | ||
countryCode: 'AU', | ||
state: 'NSW', | ||
locality: 'Sydney', | ||
validity: 3650, | ||
}); | ||
await fs.mkdir(caFolder, { recursive: true }); | ||
await fs.writeFile(caFile, ca.cert, failIfExistsFileOptions); | ||
await fs.writeFile(caKey, ca.key, failIfExistsFileOptions); | ||
return ca; | ||
} | ||
}; | ||
|
||
async function createCerts() { | ||
const ca = await getOrCreateCA(); | ||
const cert = await createCert({ | ||
ca: { key: ca.key, cert: ca.cert }, | ||
domains, | ||
validity: 3650, | ||
}); | ||
await fs.writeFile(certFile, `${cert.cert}${ca.cert}`, overwriteFileOptions); | ||
await fs.writeFile(certKey, cert.key, overwriteFileOptions); | ||
|
||
console.log('New certificate saved.'); | ||
} | ||
|
||
createCerts(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<title>Homepage</title> | ||
<link rel="preconnect" href="https://fonts.googleapis.com" /> | ||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> | ||
<link | ||
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" | ||
rel="stylesheet" | ||
/> | ||
<script src="https://cdn.integ.uidapi.com/uid2-sdk-3.3.2.js"></script> | ||
<link href="../style.scss" rel="stylesheet" /> | ||
<script src="./auth.tsx" defer="defer"></script> | ||
</head> | ||
<body> | ||
<div id="app"></div> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { createApp } from '../shared/createApp'; | ||
import { Layout } from '../shared/layout'; | ||
import { setUid2Identity, useUid2Identity } from '../shared/uid2Identity'; | ||
import type { Identity } from '../../src/exports'; | ||
import { FormEventHandler, useState } from 'react'; | ||
import { getEmailCookie, setEmailCookie } from '../shared/user'; | ||
import { initUid2Sdk } from '../shared/uid2Helper'; | ||
import { devSiteMap } from '../siteDetails'; | ||
|
||
initUid2Sdk(); | ||
const mainSiteUrl = devSiteMap.www.url; | ||
|
||
type LoggedInProps = Readonly<{ identity: Identity; email?: string }>; | ||
function LoggedIn({ identity, email }: LoggedInProps) { | ||
return ( | ||
<div> | ||
<div>Advertising token: {identity.advertising_token}</div> | ||
<div> | ||
Email: {!!email && email} | ||
{!email && '<Not logged in>'} | ||
</div> | ||
<div> | ||
<a href={mainSiteUrl}>Back to the main site</a> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
type LoginFormProps = Readonly<{ | ||
setEmail: (email: string) => void; | ||
}>; | ||
function LoginForm({ setEmail }: LoginFormProps) { | ||
const handleSubmit: FormEventHandler<HTMLFormElement> = async (e) => { | ||
e.preventDefault(); | ||
const email = (e.currentTarget.elements as any).email.value; | ||
if (email) { | ||
console.log(`Sending CSTG request for ${email}...`); | ||
await setUid2Identity(email); | ||
console.log(`CSTG request for ${email} complete`); | ||
setEmailCookie(email); | ||
setEmail(email); | ||
} | ||
}; | ||
return ( | ||
<form onSubmit={handleSubmit}> | ||
<input type='text' id='email' /> | ||
<button type='submit'>Log in</button> | ||
</form> | ||
); | ||
} | ||
|
||
function Auth() { | ||
const [email, setEmail] = useState(getEmailCookie()); | ||
const identity = useUid2Identity(); | ||
return ( | ||
<div> | ||
{!!identity && <LoggedIn identity={identity} email={email} />} | ||
{!identity && <LoginForm setEmail={setEmail} />} | ||
</div> | ||
); | ||
} | ||
|
||
createApp( | ||
<Layout siteName='auth'> | ||
<div className='content'> | ||
<Auth /> | ||
</div> | ||
</Layout> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import Webpack from 'webpack'; | ||
import WebpackDevServer from 'webpack-dev-server'; | ||
import webpackConfig from './webpack.config.js'; | ||
import { devSites } from './siteDetails.js'; | ||
|
||
// @ts-ignore | ||
const compiler = Webpack(webpackConfig); | ||
const hosts = Object.fromEntries( | ||
devSites.map((s) => [s.domain, { ...s, index: `/${s.name}.html` }]) | ||
); | ||
const hostnames = Object.keys(hosts); | ||
const devServerOptions = { | ||
...webpackConfig.devServer, | ||
historyApiFallback: { | ||
verbose: true, | ||
rewrites: [ | ||
{ | ||
from: /^[^.]+$/, | ||
to: (context: any) => { | ||
const hostname = context.request.header('Host'); | ||
return hosts[hostname].index; | ||
}, | ||
}, | ||
], | ||
}, | ||
open: hostnames.map((host) => `https://${host}/`), | ||
port: 443, | ||
allowedHosts: hostnames, | ||
server: { | ||
type: 'https', | ||
options: { | ||
ca: '../ca/ca.crt', | ||
cert: '../ca/cert.crt', | ||
key: '../ca/cert.key', | ||
}, | ||
}, | ||
}; | ||
const server = new WebpackDevServer(devServerOptions, compiler); | ||
|
||
const runServer = async () => { | ||
console.log('Starting server...'); | ||
await server.start(); | ||
}; | ||
|
||
runServer(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { createRoot } from 'react-dom/client'; | ||
|
||
function domReady(callBack: () => void) { | ||
document.addEventListener('DOMContentLoaded', callBack); | ||
if (document.readyState === 'interactive' || document.readyState === 'complete') { | ||
callBack(); | ||
} | ||
} | ||
|
||
export function createApp(app: React.ReactNode) { | ||
let appCreated = false; | ||
domReady(() => { | ||
if (appCreated) return; | ||
appCreated = true; | ||
const root = createRoot(document.getElementById('app')!); | ||
root.render(app); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
type LayoutProps = Readonly< | ||
React.PropsWithChildren & { siteName: string; extraHeader?: React.ReactNode } | ||
>; | ||
export function Layout({ children, siteName, extraHeader }: LayoutProps) { | ||
return ( | ||
<> | ||
<div className='header'> | ||
<h1>UID2 local dev setup: {siteName}</h1> | ||
</div> | ||
{extraHeader} | ||
<div className='content'>{children}</div> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import type { UID2, SDKSetup, CallbackHandler } from '../../src/uid2Sdk'; | ||
|
||
declare global { | ||
interface Window { | ||
__uid2: UID2 | SDKSetup | undefined; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { UID2 } from '../../src/uid2Sdk'; | ||
import { topLevelDomain } from '../siteDetails'; | ||
|
||
export function isUid2Sdk(sdk: any): sdk is UID2 { | ||
if (typeof sdk?.init === 'function') return true; | ||
return false; | ||
} | ||
|
||
export function initUid2Sdk() { | ||
window.__uid2 = window.__uid2 ?? { callbacks: [] }; | ||
window.__uid2.callbacks?.push((event) => { | ||
if (event === 'SdkLoaded') { | ||
(window.__uid2 as UID2).init({ | ||
baseUrl: 'https://operator-integ.uidapi.com', | ||
cookieDomain: topLevelDomain, | ||
useCookie: true, | ||
}); | ||
} | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { useEffect, useState } from 'react'; | ||
import type { Identity, CallbackHandler } from '../../src/exports'; | ||
import { UID2 } from '../../src/uid2Sdk'; | ||
import { isUid2Sdk } from './uid2Helper'; | ||
|
||
export function useUid2Identity() { | ||
const [user, setUser] = useState<Identity | null>(null); | ||
const uid2Handler: CallbackHandler = (_, payload) => { | ||
if (payload.identity) { | ||
setUser(payload.identity); | ||
} else { | ||
setUser(null); | ||
} | ||
}; | ||
useEffect(() => { | ||
window.__uid2 = window.__uid2 ?? { callbacks: [] }; | ||
window.__uid2.callbacks!.push(uid2Handler); | ||
return () => { | ||
const handlerIndex = window.__uid2?.callbacks?.indexOf(uid2Handler); | ||
if (!handlerIndex) return; | ||
window.__uid2?.callbacks?.splice(handlerIndex, 1); | ||
}; | ||
}, []); | ||
return user; | ||
} | ||
|
||
export function setUid2Identity(email: string) { | ||
if (!isUid2Sdk(window.__uid2)) throw Error('SDK not available'); | ||
return window.__uid2.setIdentityFromEmail(email, { | ||
serverPublicKey: | ||
'UID2-X-I-MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENLGSNRNncEb0D2FAaws7ZuymOBYAc7eKN53mady4sBiWCFRyRIB4sgHvBm1TsC8OLbLK41vHqRutoOaNp44YBA==', | ||
subscriptionId: 'T3NaRGYBaG', | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { topLevelDomain } from '../siteDetails'; | ||
|
||
const emailStorageKey = 'loggedInUserEmail'; | ||
|
||
export function setEmailCookie(email: string) { | ||
const cookie = `${emailStorageKey}=${encodeURIComponent( | ||
)};domain=${topLevelDomain};max-age=86400;`; | ||
document.cookie = cookie; | ||
} | ||
|
||
export function getEmailCookie() { | ||
const docCookie = document.cookie; | ||
if (docCookie) { | ||
const payload = docCookie.split('; ').find((row) => row.startsWith(emailStorageKey + '=')); | ||
if (payload) { | ||
return decodeURIComponent(payload.split('=')[1]); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
const sites = [ | ||
{ | ||
name: 'www', | ||
domain: 'www.uid2-local-dev-setup.com', | ||
}, | ||
{ | ||
name: 'auth', | ||
domain: 'auth.uid2-local-dev-setup.com', | ||
}, | ||
]; | ||
|
||
export const devSites = sites.map((s) => ({ ...s, url: `https://${s.domain}/` })); | ||
|
||
export const devDomains = Object.values(devSites).map((s) => s.domain); | ||
|
||
export const devSiteMap = Object.fromEntries(devSites.map((s) => [s.name, s])); | ||
|
||
export const topLevelDomain = 'uid2-local-dev-setup.com'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
body { | ||
font-family: 'Roboto', sans-serif; | ||
font-weight: 400; | ||
font-style: normal; | ||
|
||
line-height: 1.88889; | ||
color: #0a1300; | ||
background: #bacdd8; | ||
margin: 0; | ||
padding: 0; | ||
width: 100%; | ||
|
||
.app { | ||
width: 100%; | ||
} | ||
|
||
.header { | ||
width: 100%; | ||
display: flex; | ||
justify-content: center; | ||
padding: 0; | ||
} | ||
|
||
.content { | ||
padding: 20px; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"$schema": "https://json.schemastore.org/tsconfig", | ||
"display": "Node 16", | ||
|
||
"compilerOptions": { | ||
"lib": ["es2021", "dom"], | ||
"module": "commonjs", | ||
"target": "es6", | ||
"allowJs": true, | ||
"strict": true, | ||
"esModuleInterop": true, | ||
"skipLibCheck": true, | ||
"declaration": true, | ||
"moduleResolution": "node", | ||
"resolveJsonModule": true, | ||
"outDir": "lib", | ||
"sourceMap": true, | ||
"typeRoots": ["../node_modules/@types"], | ||
"jsx": "react-jsx" | ||
}, | ||
"include": ["."], | ||
"exclude": ["../node_modules", "dist"] | ||
} |
Oops, something went wrong.