Merge pull request #29 from tlsnotary/1-click-changes

1 Click Plugin changes
This commit is contained in:
Tanner
2025-05-06 05:10:28 -07:00
committed by GitHub
16 changed files with 96 additions and 169 deletions

View File

@@ -9,7 +9,7 @@ COPY . .
RUN apt-get update && apt-get install -y curl && apt-get install netcat-openbsd -y
RUN curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y
RUN npm install
RUN npm i --prefix rs/0.1.0-alpha.9/
RUN npm i --prefix rs/0.1.0-alpha.10/
RUN npm run build
EXPOSE ${PORT}

18
package-lock.json generated
View File

@@ -38,7 +38,7 @@
"redux-thunk": "^2.4.2",
"stream-browserify": "^3.0.0",
"tailwindcss": "^3.4.13",
"tlsn-js": "^0.1.0-alpha.9"
"tlsn-js": "^0.1.0-alpha.10"
},
"devDependencies": {
"@babel/core": "^7.25.2",
@@ -19527,22 +19527,20 @@
"license": "MIT"
},
"node_modules/tlsn-js": {
"version": "0.1.0-alpha.9",
"resolved": "https://registry.npmjs.org/tlsn-js/-/tlsn-js-0.1.0-alpha.9.tgz",
"integrity": "sha512-aEg/Pkdj0Oz9fB3xMUv67Lq69yLbuNS6IzA9j2lDwAmzOfgRBS7ZptcGuLz1hWoNvF1ma7JvdAJpHpL0ee8dkQ==",
"license": "ISC",
"version": "0.1.0-alpha.10.0",
"resolved": "https://registry.npmjs.org/tlsn-js/-/tlsn-js-0.1.0-alpha.10.0.tgz",
"integrity": "sha512-+kwcT5AISESGmSI4sZ3rZ4VqOB/ogadTBisKB8yT8j8l5RqeI3xW+gZ+gF6ZE/Y4zEtXe3d6CbZFU11lEaAo0g==",
"dependencies": {
"tlsn-wasm": "^0.1.0-alpha.9"
"tlsn-wasm": "0.1.0-alpha.10"
},
"engines": {
"node": ">= 16.20.2"
}
},
"node_modules/tlsn-wasm": {
"version": "0.1.0-alpha.9",
"resolved": "https://registry.npmjs.org/tlsn-wasm/-/tlsn-wasm-0.1.0-alpha.9.tgz",
"integrity": "sha512-/7DKVXzFdlzD9vwsROb/tvGHJ+xHlAbvaVjMGBWOrecG5KR+Dcg6QMSb4R0/2jePX6u8r6JNXbRpKgQ+yf1zaA==",
"license": "MIT OR Apache-2.0"
"version": "0.1.0-alpha.10",
"resolved": "https://registry.npmjs.org/tlsn-wasm/-/tlsn-wasm-0.1.0-alpha.10.tgz",
"integrity": "sha512-HgGLmaxyw18v34hxAOnVc9P/HuEjVuQeb/6TcskaSHGFOY2t2pjWBz93toinEAD2N1LwVQJXoECxsP5Qo81Haw=="
},
"node_modules/to-buffer": {
"version": "1.1.1",

View File

@@ -53,7 +53,7 @@
"redux-thunk": "^2.4.2",
"stream-browserify": "^3.0.0",
"tailwindcss": "^3.4.13",
"tlsn-js": "^0.1.0-alpha.9"
"tlsn-js": "^0.1.0-alpha.10"
},
"devDependencies": {
"@babel/core": "^7.25.2",
@@ -108,4 +108,4 @@
"webpack-dev-server": "^4.11.1"
},
"homepage": ""
}
}

View File

@@ -684,9 +684,9 @@ dependencies = [
[[package]]
name = "rangeset"
version = "0.1.0"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e60e90dbde8afa699f8956a7f29b6533b860963ef9c7a7e993e145ffa6f7e0c"
checksum = "1fc7af00a06ad692080d87495a904677592c662610edb82b4fc8782f4ed2f01f"
dependencies = [
"serde",
]
@@ -942,8 +942,8 @@ dependencies = [
[[package]]
name = "tlsn-core"
version = "0.1.0-alpha.9"
source = "git+https://github.com/tlsnotary/tlsn.git?tag=v0.1.0-alpha.9#328c2af1623f742e49ab62f49dcde606f933056f"
version = "0.1.0-alpha.10"
source = "git+https://github.com/tlsnotary/tlsn.git?tag=v0.1.0-alpha.10#de7a47de5b4f6e4de0ec2ff3d1c42a0d2bf7a6a6"
dependencies = [
"bcs",
"bimap",
@@ -969,8 +969,8 @@ dependencies = [
[[package]]
name = "tlsn-tls-core"
version = "0.1.0-alpha.9"
source = "git+https://github.com/tlsnotary/tlsn.git?tag=v0.1.0-alpha.9#328c2af1623f742e49ab62f49dcde606f933056f"
version = "0.1.0-alpha.10"
source = "git+https://github.com/tlsnotary/tlsn.git?tag=v0.1.0-alpha.10#de7a47de5b4f6e4de0ec2ff3d1c42a0d2bf7a6a6"
dependencies = [
"futures",
"hmac",
@@ -989,7 +989,7 @@ dependencies = [
[[package]]
name = "tlsn-utils"
version = "0.1.0"
source = "git+https://github.com/tlsnotary/tlsn-utils?rev=6650a95#6650a956d3597d3a662fd9c15a64a1651afac399"
source = "git+https://github.com/tlsnotary/tlsn-utils?rev=6168663#6168663495281f2c1b2c1734dc276cecc4d36ef1"
[[package]]
name = "tracing"

View File

@@ -19,4 +19,4 @@ serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0"
hex = "0.4"
bincode = { version = "1.3" }
tlsn-core = { git = "https://github.com/tlsnotary/tlsn.git", tag = "v0.1.0-alpha.9", package = "tlsn-core" }
tlsn-core = { git = "https://github.com/tlsnotary/tlsn.git", tag = "v0.1.0-alpha.10", package = "tlsn-core" }

BIN
rs/0.1.0-alpha.10/index.node Executable file

Binary file not shown.

Binary file not shown.

View File

@@ -7,7 +7,7 @@ import configureAppStore, { AppRootState } from '../web/store';
import { Provider } from 'react-redux';
import { Mutex } from 'async-mutex';
//@ts-ignore
import { verify } from '../rs/0.1.0-alpha.9/index.node';
import { verify } from '../rs/0.1.0-alpha.10/index.node';
import { convertNotaryWsToHttp, fetchPublicKeyFromNotary } from './util/index';
import { assignPoapToUser } from './util/index';
@@ -43,7 +43,7 @@ app.get('*', (req, res) => {
const storeConfig: AppRootState = {
attestation: {
raw: {
version: '0.1.0-alpha.9',
version: '0.1.0-alpha.10',
data: '',
meta: {
notaryUrl: '',

View File

@@ -12,15 +12,11 @@ import { formatDataPreview } from '../../utils/utils';
const steps = [
'Connect Extension',
'Install Plugin',
'Run Plugin',
'Verify Attestation',
'🎉 Claim POAP 🎉',
];
export default function Steps(): ReactElement {
const [extensionInstalled, setExtensionInstalled] = useState(false);
const [pluginID, setPluginID] = useState('');
const [step, setStep] = useState<number>(0);
const [client, setClient] = useState<any>(null);
const [pluginData, setPluginData] = useState<PresentationJSON | null>(null);
@@ -35,7 +31,6 @@ export default function Steps(): ReactElement {
}
}, [step]);
useEffect(() => {
const checkExtension = () => {
//@ts-ignore
@@ -66,7 +61,9 @@ export default function Steps(): ReactElement {
const match = transcript.recv.match(/"screen_name":"([^"]+)"/);
const screenName = match ? match[1] : null;
setScreenName(screenName);
setExploding(true);
if (screenName) {
setExploding(true);
}
}
}, [transcript]);
@@ -80,57 +77,32 @@ export default function Steps(): ReactElement {
}
}
async function handleGetPlugins() {
try {
const plugins = await client.getPlugins('**', '**');
const targetPlugin = plugins.find(
(plugin: any) =>
plugin.title === 'Twitter Profile' &&
Array.isArray(plugin.headers) &&
plugin.headers.includes(
'https://api.x.com/1.1/account/settings.json',
),
);
if (targetPlugin) {
setPluginID(targetPlugin.hash);
setStep(2);
}
} catch (error) {
console.error(error);
}
}
async function handlePluginInstall() {
try {
const plugin = await client.installPlugin(
'https://github.com/tlsnotary/tlsn-extension/raw/main/src/assets/plugins/twitter_profile.wasm',
);
setPluginID(plugin);
setStep(2);
} catch (error: any) {
console.log(error.message);
if (error.message === 'Plugin already exist.') {
try {
await handleGetPlugins();
} catch (error) {
console.log(error);
}
}
console.log(error);
}
}
async function handleRunPlugin() {
try {
setLoading(true);
const pluginData = await client.runPlugin(pluginID);
setLoading(false);
const pluginData = await client.runPlugin(
'https://github.com/tlsnotary/tlsn-extension/raw/main/src/assets/plugins/twitter_profile.wasm'
);
setPluginData(pluginData);
setStep(3);
const response = await fetch('/verify-attestation', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ attestation: pluginData }),
});
if (response.status === 200) {
const data = await response.json();
setTranscript(data.presentationObj);
setStep(1); // Stay on Run Plugin step
} else {
console.log(await response.text());
}
} catch (error) {
setLoading(false);
console.log(error);
} finally {
setLoading(false);
}
}
@@ -165,14 +137,7 @@ export default function Steps(): ReactElement {
Connect
</button>
)}
{step === 1 && (
<div className="flex flex-col gap-2">
<button onClick={handlePluginInstall} className="button">
Install Plugin
</button>
</div>
)}
{step === 2 && (
{step === 1 && !pluginData && (
<div className="flex flex-col items-center justify-center gap-2">
<ul className="flex flex-col items-center justify-center gap-1">
<li className="text-base font-light">
@@ -187,8 +152,8 @@ export default function Steps(): ReactElement {
notarization is finished
</li>
<li className="text-base font-light">
If successful the attestation field will populate with the
attestation from the notary
If successful, the attestation and verified data will be
displayed below
</li>
</ul>
<Button onClick={handleRunPlugin} loading={loading}>
@@ -196,40 +161,21 @@ export default function Steps(): ReactElement {
</Button>
</div>
)}
{step === 3 && (
<div>
<ul className="flex flex-col justify-center items-center gap-1">
<li className="text-base font-light">
Click the "Verify" button below to verify the attestation
</li>
<li className="text-base font-light">
If successful the verified data will show in the
Presentation field and provide you with a link to claim your
POAP
</li>
</ul>
{step === 1 && pluginData && screenName && (
<div className="flex flex-col items-center justify-center gap-2">
<h3 className="text-lg font-semibold text-center">
Optional: Claim Your POAP
</h3>
<ClaimPoap screen_name={screenName} exploding={exploding} />
</div>
)}
{step === 5 && (
<>
<ClaimPoap
screen_name={screenName}
exploding={exploding}
setStep={setStep}
/>
</>
)}
</div>
{pluginData ? (
{pluginData && (
<DisplayPluginData
step={step}
pluginData={pluginData}
transcript={transcript}
setTranscript={setTranscript}
setStep={setStep}
/>
) : (
<></>
)}
</>
) : (
@@ -243,38 +189,13 @@ function DisplayPluginData({
step,
pluginData,
transcript,
setTranscript,
setStep,
}: {
step: number;
pluginData: any;
transcript: any;
setTranscript: any;
setStep: any;
}): ReactElement {
const [tab, setTab] = useState<'sent' | 'recv'>('sent');
async function handleVerify() {
try {
const response = await fetch('/verify-attestation', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ attestation: pluginData }),
});
if (response.status === 200) {
const data = await response.json();
setTranscript(data.presentationObj);
setStep(5);
} else {
console.log(await response.text());
}
} catch (error) {
console.log(error);
}
}
return (
<div className="flex justify-center items-center space-x-4 mt-8">
<div className="w-96">
@@ -287,9 +208,6 @@ function DisplayPluginData({
</pre>
</div>
</div>
<button disabled={step !== 3} onClick={handleVerify} className="button">
Verify
</button>
<div className="w-96">
<div className="p-2 bg-gray-200 border-t rounded-t-md text-center text-lg font-semibold">
Presentation
@@ -327,35 +245,37 @@ function ClaimPoap({
}: {
screen_name: string;
exploding: boolean;
setStep: any;
}): ReactElement {
const [poapLink, setPoapLink] = useState<string>('');
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState<boolean>(false);
useEffect(() => {
const handleClaimPoap = async () => {
try {
if (!screen_name) return;
const response = await fetch('/poap-claim', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ screenName: screen_name }),
});
if (response.status === 200) {
const data = await response.json();
setPoapLink(data.poapLink);
} else {
setError(await response.text());
}
} catch (error) {
console.log(error);
const handleClaimPoap = async () => {
setLoading(true);
setError(null);
try {
if (!screen_name) return;
const response = await fetch('/poap-claim', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ screenName: screen_name }),
});
if (response.status === 200) {
const data = await response.json();
setPoapLink(data.poapLink);
} else {
const errorText = await response.text();
setError(errorText || 'Failed to claim POAP');
}
};
handleClaimPoap();
}, [screen_name]);
} catch (error) {
console.error('Error claiming POAP:', error);
setError('Failed to connect to the server');
} finally {
setLoading(false);
}
};
const mediumProps: ConfettiProps = {
force: 0.6,
@@ -366,13 +286,22 @@ function ClaimPoap({
};
return (
<div>
{poapLink !== '' && (
<a className="button" href={poapLink} target="_blank">
<div className="flex flex-col items-center gap-2">
{!poapLink && !error && (
<Button
onClick={handleClaimPoap}
loading={loading}
>
Claim POAP!
</Button>
)}
{poapLink && (
<a className="button" href={poapLink} target="_blank">
View Your POAP!
</a>
)}
{exploding && <ConfettiExplosion {...mediumProps} />}
{error && <p className="text-red-500">Error: {error}</p>}
{exploding && poapLink && <ConfettiExplosion {...mediumProps} />}
</div>
);
}

View File

@@ -21,7 +21,7 @@ export type State = {
export const initState: State = {
raw: {
version: '0.1.0-alpha.9',
version: '0.1.0-alpha.10',
data: '',
meta: {
notaryUrl: '',

View File

@@ -1,5 +1,5 @@
export interface AttestedData {
version: '0.1.0-alpha.9' | '0.1.0-alpha.8' | '0.1.0-alpha.7' | '0.1.0-alpha.5';
version: '0.1.0-alpha.10' | '0.1.0-alpha.9' | '0.1.0-alpha.8' | '0.1.0-alpha.7' | '0.1.0-alpha.5';
time: number;
sent: string;
recv: string;
@@ -10,7 +10,7 @@ export interface AttestedData {
}
export type Attestation = {
version: '0.1.0-alpha.9' | '0.1.0-alpha.8' | '0.1.0-alpha.7';
version: '0.1.0-alpha.10' | '0.1.0-alpha.9' | '0.1.0-alpha.8' | '0.1.0-alpha.7';
data: string;
meta: {
notaryUrl: string;