Initial commit

This commit is contained in:
yigid balaban 2024-10-01 22:56:10 +03:00
commit 18d1a02e98
Signed by: fyb
GPG Key ID: CF1BBD1336C0A3D6
9 changed files with 2978 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules/

2
dist/bundle.js vendored Normal file

File diff suppressed because one or more lines are too long

1291
dist/bundle.js.LICENSE.txt vendored Normal file

File diff suppressed because it is too large Load Diff

21
index.html Normal file
View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>ZKL Roadhog Demo</title>
</head>
<body>
<script src="dist/bundle.js"></script>
<script>
window.addEventListener('load', function () {
document.getElementById('metamask').disabled = false;
document.getElementById('phantom').disabled = false;
});
</script>
<h1>ZKL Roadhog Demo</h1>
<button disabled id="metamask" onclick="signIn('ethereum')">sign in with metamask</button>
<button disabled id="phantom" onclick="signIn('solana')">sign in with solana</button>
</body>
</html>

35
index.js Normal file
View File

@ -0,0 +1,35 @@
import { signIn as _signIn } from './roadhog.js';
const endpoint = "http://localhost:3000";
async function signIn(type) {
try {
const result = await _signIn(type);
if (result.success) {
console.log('Successfully signed in with', type);
const b = document.createElement('button');
b.innerText = 'Click to access protected';
b.setAttribute('onclick', 'fetchProtected()');
document.body.appendChild(b);
} else {
console.error('Sign-in failed:', result.error);
}
} catch (error) {
console.error('Sign-in error:', error);
}
}
async function signOff() {
}
window.signIn = signIn;
window.signOff = signOff;
function init() {
console.log('start');
if (!window.ethereum) console.log('ethereum not detected');
if (!window.solana) console.log('solana not detected');
}
window.addEventListener('load', init);

13
package.json Normal file
View File

@ -0,0 +1,13 @@
{
"devDependencies": {
"terser-webpack-plugin": "^5.3.10",
"webpack": "^5.95.0",
"webpack-cli": "^5.1.4"
},
"dependencies": {
"@solana/web3.js": "^1.95.3",
"bs58": "^6.0.0",
"ethers": "^6.13.3",
"siwe": "^2.3.2"
}
}

1502
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

88
roadhog.js Normal file
View File

@ -0,0 +1,88 @@
import { SiweMessage } from 'siwe';
import { BrowserProvider, JsonRpcSigner } from 'ethers';
import * as solanaWeb3 from '@solana/web3.js';
import bs58 from 'bs58';
const endpoint = 'http://localhost:3000';
export async function signIn(type) {
let address, signature, message;
if (type === 'ethereum') {
await window.ethereum.request({ method: 'eth_requestAccounts' });
const provider = new BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
address = await signer.getAddress();
const nonceResponse = await fetch(`${endpoint}/auth/nonce?address=${address}&type=ethereum`);
const { nonce } = await nonceResponse.json();
const siweMessage = new SiweMessage({
domain: window.location.host,
address: address,
statement: 'Sign in with Ethereum to zk-Lokomotive.',
uri: window.location.origin,
version: '1',
chainId: 1,
nonce: nonce
});
message = siweMessage.prepareMessage();
signature = await signer.signMessage(message);
} else if (type === 'solana') {
const provider = window.solana;
await provider.connect();
address = provider.publicKey.toString();
const nonceResponse = await fetch(`${endpoint}/auth/nonce?address=${address}&type=solana`);
const { nonce } = await nonceResponse.json();
const encodedMessage = new TextEncoder().encode(nonce);
const signatureBytes = await provider.signMessage(encodedMessage, 'utf8');
signature = bs58.encode(signatureBytes.signature);
} else {
throw new Error('Invalid type');
}
try {
const response = await fetch(`${endpoint}/auth/verify`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ type, message, address, signature }),
});
if (!response.ok) {
throw new Error((await response.json()).error);
}
const { auth_token } = await response.json();
localStorage.setItem('auth_token', auth_token);
localStorage.setItem('auth_type', type);
return { success: true, auth_token };
} catch (error) {
console.error('Authentication error:', error);
return { success: false, error: error.message };
}
}
export async function signOff() {
const auth_token = localStorage.getItem('auth_token');
const response = await fetch(`${endpoint}/auth/signoff`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${auth_token}`
}
});
if (!response.ok) {
throw new Error((await response.json()).error);
} else {
localStorage.removeItem('auth_token');
return true;
}
}

25
webpack.config.js Normal file
View File

@ -0,0 +1,25 @@
const path = require("path");
const webpack = require("webpack");
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
entry: "./index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist")
},
plugins: [
new TerserPlugin({
terserOptions: {
keep_fnames: ['signIn', 'fetchProtected'],
mangle: {
reserved: [
"signIn",
"fetchProtected"
]
}
}
})
],
mode: "development"
};