Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Next Steps #2

Open
wants to merge 81 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
bd2fad2
chore(deps): correct safe-sdk, supabase, octokit
Keyrxng Jun 24, 2024
ba86ab3
chore: basic github login
Keyrxng Jun 24, 2024
7e4084a
chore: e2e creation with basic ui display
Keyrxng Jun 27, 2024
949ec35
chore: remove prompt
Keyrxng Jun 27, 2024
ae2ef16
fix: no requests before login
Keyrxng Jun 27, 2024
9269b87
chore: remove keygen logics
Keyrxng Jul 3, 2024
58cf658
chore: minor fixes
Keyrxng Jul 3, 2024
647b16a
chore: use new pk/passkey module flow
Keyrxng Jul 3, 2024
64d66d0
chore: hide privateKey
Keyrxng Jul 3, 2024
b513525
chore: add wallet funding with faucet
Keyrxng Jul 3, 2024
9e802cb
chore: basic toast for while funding
Keyrxng Jul 3, 2024
d6cdb84
chore: hardcode env vars temporarily
Keyrxng Jul 6, 2024
7e9f4fa
chore: improve funding for demo
Keyrxng Jul 6, 2024
0fd5a17
chore: webauthn-signer pkg
Keyrxng Jul 6, 2024
2cd989a
chore: remove readme
Keyrxng Jul 6, 2024
ebc3372
chore: dependencies
Keyrxng Jul 7, 2024
2bed06e
chore: simpler function flow
Keyrxng Jul 7, 2024
557dc3e
chore: webauthn register
Keyrxng Jul 7, 2024
167ac4a
chore: webauthn authenticate
Keyrxng Jul 7, 2024
1e06e1a
chore: webauthn user handling
Keyrxng Jul 7, 2024
9a183be
chore: move toast
Keyrxng Jul 7, 2024
73c54af
chore: move funding
Keyrxng Jul 7, 2024
9e6c184
chore: auth user and session split
Keyrxng Jul 7, 2024
3bc155f
chore: existing cred type
Keyrxng Jul 7, 2024
dc4edaa
chore: create-next-app with supabase template
Keyrxng Jul 7, 2024
eb710f1
chore: update server client cookies
Keyrxng Jul 7, 2024
fde0ae0
chore: update middleware
Keyrxng Jul 7, 2024
05fc29b
chore: turbopack, env vars, error pages
Keyrxng Jul 7, 2024
05b2f5a
chore: remove template components
Keyrxng Jul 7, 2024
7214da8
chore: claim portal icons
Keyrxng Jul 7, 2024
ac71c5f
chore: commit hash component
Keyrxng Jul 7, 2024
8590598
chore: original grid component
Keyrxng Jul 7, 2024
a645604
chore: refactored grid component
Keyrxng Jul 7, 2024
da04f27
chore: add pay.ubq.fi css
Keyrxng Jul 7, 2024
c3633b0
chore: original claim portal
Keyrxng Jul 7, 2024
42f55f4
chore: media, favicon etc
Keyrxng Jul 7, 2024
fc10696
chore: rpc-handler and css
Keyrxng Jul 7, 2024
c6c5d00
chore: page and layout
Keyrxng Jul 7, 2024
6d4466c
chore: appstate, buttonController, toaster
Keyrxng Jul 7, 2024
ad45b33
chore: add claim portal scripts
Keyrxng Jul 7, 2024
3d2003a
chore: update grid css selector, import styles
Keyrxng Jul 7, 2024
806ec71
chore: pay.ubq UI and logic running
Keyrxng Jul 7, 2024
e5ef4c2
chore: working oauth
Keyrxng Jul 7, 2024
20db6e3
chore: add shadcn for quick components
Keyrxng Jul 7, 2024
73cb784
chore: move grid into layout
Keyrxng Jul 7, 2024
21e34ba
chore: move claim comps into /claim
Keyrxng Jul 8, 2024
2a16e4e
chore: remove buttons from toaster, add dropdown-menu
Keyrxng Jul 8, 2024
05c8b90
chore: navbar and user auth
Keyrxng Jul 8, 2024
d0e1287
chore: auth actions into layout and remove /login
Keyrxng Jul 8, 2024
2e9835b
chore: scripts from static
Keyrxng Jul 8, 2024
cb845b3
chore: api/auth
Keyrxng Jul 8, 2024
1e3bab3
chore: simple home with auth/nav
Keyrxng Jul 8, 2024
a1e1938
chore: remove middleware auth checks temp
Keyrxng Jul 8, 2024
5fae9c5
chore: octo auth from oauth, github auth user
Keyrxng Jul 8, 2024
6f7b19e
chore: remove static, move next-ui to root
Keyrxng Jul 9, 2024
684bf5e
chore: fix repo structure
Keyrxng Jul 9, 2024
41f1730
chore: split components into server, client, shared
Keyrxng Jul 9, 2024
7abf2ab
chore: scripts into lib
Keyrxng Jul 9, 2024
2722ed8
chore: fix imports
Keyrxng Jul 9, 2024
a834047
feat: full passkey auth flow
Keyrxng Jul 10, 2024
3ef3ce5
feat: account profile
Keyrxng Jul 10, 2024
7e57148
chore: tabbed UI
Keyrxng Jul 10, 2024
33008f5
chore: return signer data vs signer object
Keyrxng Jul 10, 2024
a50dbcc
feat: breadcrumbs
Keyrxng Jul 10, 2024
49d8928
chore: ui for create/manage passkey & account
Keyrxng Jul 10, 2024
eea10ee
chore: v basic funds ui
Keyrxng Jul 10, 2024
be34697
chore: code split
Keyrxng Jul 10, 2024
843d3d0
chore: minor fixes for build
Keyrxng Jul 10, 2024
f983df9
chore: eslint, prettier, cspell
Keyrxng Jul 10, 2024
c6569de
feat: integrate faucet funding
Keyrxng Jul 10, 2024
5a32a8c
chore: build ready
Keyrxng Jul 10, 2024
c0b342e
chore(deps): bump webauthn-evm-signer
Keyrxng Jul 10, 2024
22ed0f0
chore: use cur origin for rpId
Keyrxng Jul 10, 2024
ba902ef
chore: remove readme
Keyrxng Jul 10, 2024
fb969d0
chore: remove build and deploy workflows
Keyrxng Jul 10, 2024
8e5f20a
chore: remove unused searchParams
Keyrxng Jul 10, 2024
f68b518
chore: minor fixes
Keyrxng Jul 11, 2024
af54f61
feat: server side eoa transfers
Keyrxng Jul 11, 2024
aa748bd
chore: env and packages
Keyrxng Jul 15, 2024
71563d0
chore: minor fixes
Keyrxng Jul 15, 2024
c2eb982
feat: mint wxdai, generate permits, transfer improvement
Keyrxng Jul 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
chore: basic github login
  • Loading branch information
Keyrxng committed Jun 24, 2024
commit ba86ab35d35405fb06cb11236770ad03b556922a
56 changes: 54 additions & 2 deletions build/esbuild-build.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { execSync } from "child_process";
import esbuild from "esbuild";
import { config } from "dotenv";
config()

const typescriptEntries = ["static/main.ts"];
// const cssEntries = ["static/style.css"];
const cssEntries = ["static/style.css"];

const entries = [
...typescriptEntries,
// ...cssEntries
...cssEntries
];

export const esBuildContext: esbuild.BuildOptions = {
Expand All @@ -20,6 +25,11 @@ export const esBuildContext: esbuild.BuildOptions = {
".svg": "dataurl",
},
outdir: "static/dist",
define: createEnvDefines(["SUPABASE_URL", "SUPABASE_ANON_KEY"], {
SUPABASE_STORAGE_KEY: generateSupabaseStorageKey(),
commitHash: execSync(`git rev-parse --short HEAD`).toString().trim(),
NODE_ENV: process.env.NODE_ENV || "development",
}),
};

esbuild
Expand All @@ -31,3 +41,45 @@ esbuild
console.error(err);
process.exit(1);
});


function createEnvDefines(environmentVariables: string[], generatedAtBuild: Record<string, unknown>): Record<string, string> {
const defines: Record<string, string> = {};
for (const name of environmentVariables) {
const envVar = process.env[name];
if (envVar !== undefined) {
defines[name] = JSON.stringify(envVar);
} else {
throw new Error(`Missing environment variable: ${name}`);
}
}
for (const key in generatedAtBuild) {
if (Object.prototype.hasOwnProperty.call(generatedAtBuild, key)) {
defines[key] = JSON.stringify(generatedAtBuild[key]);
}
}
return defines;
}

export function generateSupabaseStorageKey(): string | null {
const SUPABASE_URL = process.env.SUPABASE_URL;
if (!SUPABASE_URL) {
console.error("SUPABASE_URL environment variable is not set");
return null;
}

const urlParts = SUPABASE_URL.split(".");
if (urlParts.length === 0) {
console.error("Invalid SUPABASE_URL environment variable");
return null;
}

const domain = urlParts[0];
const lastSlashIndex = domain.lastIndexOf("/");
if (lastSlashIndex === -1) {
console.error("Invalid SUPABASE_URL format");
return null;
}

return domain.substring(lastSlashIndex + 1);
}
1 change: 0 additions & 1 deletion static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
<link rel="stylesheet" href="style.css" />
</head>
<body>
<h1>Ubiquity TypeScript Template</h1>
<script type="module" src="dist/main.js"></script>
</body>
</html>
7 changes: 3 additions & 4 deletions static/main.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
export async function mainModule() {
console.log(`Hello from mainModule`);
}
import { authentication } from "./src/auth/authentication";

mainModule()

authentication()
.then(() => {
console.log("mainModule loaded");
})
Expand Down
18 changes: 18 additions & 0 deletions static/src/auth/authentication.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { getGitHubAccessToken } from "../github/get-access-token";
import { getGitHubUser } from "../github/get-user";
import { GitHubUser } from "../types/github";
import { renderGitHubLoginButton, renderUserInfo } from "./rendering";

export async function authentication() {
const accessToken = await getGitHubAccessToken();
if (!accessToken) {
renderGitHubLoginButton();
}

const gitHubUser: null | GitHubUser = await getGitHubUser();
if (gitHubUser) {
renderUserInfo(gitHubUser);
}
}


57 changes: 57 additions & 0 deletions static/src/auth/rendering.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { getSupabase } from "../supabase/session";
import { GitHubUser } from "../types/github";

export async function renderGitHubLoginButton() {
const existingButton = document.getElementById("login-with-github");
if (existingButton) {
return existingButton;
}
const btn = document.createElement("button");
btn.textContent = "Login with GitHub";
btn.id = "login-with-github";
btn.onclick = async () => {
const supabase = getSupabase();
const { error } = await supabase.auth.signInWithOAuth({
provider: "github",
});
if (error) {
console.error("GitHub login error", error);
}
};

document.body.appendChild(btn);
return btn;
}

export function renderUserInfo(
user: GitHubUser
) {
const newInfo = document.createElement("div");
newInfo.innerHTML = `
<div id="user-info-container">
<img id="gh-pp" src="${user.avatar_url}" alt="User avatar" />
<h2>Hello, ${user.login}</h2>
</div>
`;

const container = document.getElementById("user-info-container");
if (container) {
container.style.display = "flex";
container.style.flexDirection = "column";
container.style.alignItems = "center";
}

const logoutButton = document.createElement("button");

logoutButton.onclick = () => {
const supabase = getSupabase();
supabase.auth.signOut().then(() => {
window.location.reload();
})
};
logoutButton.textContent = "Logout";
newInfo.appendChild(logoutButton);
document.body.appendChild(newInfo);

return newInfo;
}
30 changes: 30 additions & 0 deletions static/src/github/get-access-token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { checkSupabaseSession } from "../supabase/session";

declare const SUPABASE_STORAGE_KEY: string; // @DEV: passed in at build time check build/esbuild-build.ts

export async function getGitHubAccessToken(): Promise<string | null> {
// better to use official function, looking up localstorage has flaws
const oauthToken = await checkSupabaseSession();

if (!oauthToken) {
return null;
} else if (typeof oauthToken === "string") {
// it's the access token
return oauthToken;
}

const expiresAt = oauthToken?.expires_at;
if (expiresAt) {
if (expiresAt < Date.now() / 1000) {
localStorage.removeItem(`sb-${SUPABASE_STORAGE_KEY}-auth-token`);
return null;
}
}

const accessToken = oauthToken?.provider_token;
if (accessToken) {
return accessToken;
}

return null;
}
27 changes: 27 additions & 0 deletions static/src/github/get-url-session-token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { OAuthToken } from "../types/auth";
import { getLocalStore } from "../utils/local-storage";
declare const SUPABASE_STORAGE_KEY: string; // @DEV: passed in at build time check build/esbuild-build.ts

export async function getNewSessionToken(): Promise<string | null> {
const hash = window.location.hash;
const params = new URLSearchParams(hash.substring(1)); // remove the '#' and parse
const providerToken = params.get("provider_token");
if (!providerToken) {
const error = params.get("error_description");
// supabase auth provider has failed for some reason
console.error(`GitHub login provider: ${error}`);
}
return providerToken || null;
}

export async function getSessionToken(): Promise<string | null> {
const cachedSessionToken = getLocalStore(`sb-${SUPABASE_STORAGE_KEY}-auth-token`) as OAuthToken | null;
if (cachedSessionToken) {
return cachedSessionToken.provider_token;
}
const newSessionToken = await getNewSessionToken();
if (newSessionToken) {
return newSessionToken;
}
return null;
}
36 changes: 36 additions & 0 deletions static/src/github/get-user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Octokit } from "@octokit/rest";
import { getSessionToken } from "../supabase/session";
import { GitHubUser, GitHubUserResponse } from "../types/github";
import { getLocalStore } from "../utils/local-storage";
import { OAuthToken } from "../types/auth";
declare const SUPABASE_STORAGE_KEY: string; // @DEV: passed in at build time check build/esbuild-build.ts

export async function getGitHubUser(): Promise<GitHubUser | null> {
const activeSessionToken = await getSessionToken();
return getNewGitHubUser(activeSessionToken);
}

async function getNewGitHubUser(providerToken: string | null): Promise<GitHubUser | null> {
const octokit = new Octokit({ auth: providerToken });
try {
const response = (await octokit.request("GET /user")) as GitHubUserResponse;
return response.data;
} catch (error) {
if (!!error && typeof error === "object" && "status" in error && error.status === 403) {
console.error("GitHub API error", error);
}
console.warn("You have been logged out. Please login again.", error);
}
return null;
}

export function getGitHubUserName(): string | null {
const oauthToken = getLocalStore(`sb-${SUPABASE_STORAGE_KEY}-auth-token`) as OAuthToken | null;

const username = oauthToken?.user?.user_metadata?.user_name;
if (username) {
return username;
}

return null;
}
46 changes: 46 additions & 0 deletions static/src/supabase/session.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { createClient } from "@supabase/supabase-js";
import { getLocalStore } from "../utils/local-storage";
import { OAuthToken } from "../types/auth";

declare const SUPABASE_URL: string; // @DEV: passed in at build time check build/esbuild-build.ts
declare const SUPABASE_ANON_KEY: string; // @DEV: passed in at build time check build/esbuild-build.ts
declare const SUPABASE_STORAGE_KEY: string; // @DEV: passed in at build time check build/esbuild-build.ts

export function getSupabase() {
return createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
}

export async function checkSupabaseSession() {
const oauthToken = getLocalStore(`sb-${SUPABASE_STORAGE_KEY}-auth-token`) as OAuthToken | null;
if (!oauthToken) {
const sessionToken = await getNewSessionToken();
if (sessionToken) {
return sessionToken;
}
}
return oauthToken;
}

async function getNewSessionToken(): Promise<string | null> {
const hash = window.location.hash;
const params = new URLSearchParams(hash.substring(1)); // remove the '#' and parse
const providerToken = params.get("provider_token");
if (!providerToken) {
const error = params.get("error_description");
// supabase auth provider has failed for some reason
console.error(`GitHub login provider: ${error}`);
}
return providerToken || null;
}

export async function getSessionToken(): Promise<string | null> {
const cachedSessionToken = getLocalStore(`sb-${SUPABASE_STORAGE_KEY}-auth-token`) as OAuthToken | null;
if (cachedSessionToken) {
return cachedSessionToken.provider_token;
}
const newSessionToken = await getNewSessionToken();
if (newSessionToken) {
return newSessionToken;
}
return null;
}
57 changes: 57 additions & 0 deletions static/src/types/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
export interface OAuthToken {
provider_token: string;
access_token: string;
expires_in: number;
expires_at: number;
refresh_token: string;
token_type: string;
user: {
id: string;
aud: string;
role: string;
email: string;
email_confirmed_at: string;
phone: string;
confirmed_at: string;
last_sign_in_at: string;
app_metadata: { provider: string; providers: string[] };
user_metadata: {
avatar_url: string;
email: string;
email_verified: boolean;
full_name: string;
iss: string;
name: string;
phone_verified: boolean;
preferred_username: string;
provider_id: string;
sub: string;
user_name: string;
};
identities: [
{
id: string;
user_id: string;
identity_data: {
avatar_url: string;
email: string;
email_verified: boolean;
full_name: string;
iss: string;
name: string;
phone_verified: boolean;
preferred_username: string;
provider_id: string;
sub: string;
user_name: string;
};
provider: string;
last_sign_in_at: string;
created_at: string;
updated_at: string;
},
];
created_at: string;
updated_at: string;
};
}
5 changes: 5 additions & 0 deletions static/src/types/github.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { RestEndpointMethodTypes } from "@octokit/plugin-rest-endpoint-methods";

export type GitHubUserResponse = RestEndpointMethodTypes["users"]["getByUsername"]["response"];
export type GitHubUser = GitHubUserResponse["data"];

Loading