mirror of
https://github.com/tlsnotary/tlsn-extension.git
synced 2026-01-29 08:58:01 -05:00
Compare commits
8 Commits
discord
...
plugins_cl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f309d9226d | ||
|
|
764de211f8 | ||
|
|
d3aeaf227d | ||
|
|
163a1bd4b9 | ||
|
|
8e17101d11 | ||
|
|
fddba16cf8 | ||
|
|
52cc68937b | ||
|
|
a04b3c671a |
5
.github/workflows/demo.yml
vendored
5
.github/workflows/demo.yml
vendored
@@ -69,6 +69,8 @@ jobs:
|
||||
push: ${{ env.should_publish == 'true' }}
|
||||
tags: ${{ steps.meta-prover-server.outputs.tags }}
|
||||
labels: ${{ steps.meta-prover-server.outputs.labels }}
|
||||
build-args: |
|
||||
GIT_HASH=${{ github.sha }}
|
||||
|
||||
build_and_publish_demo_frontend:
|
||||
name: build and publish demo frontend image
|
||||
@@ -103,5 +105,6 @@ jobs:
|
||||
tags: ${{ steps.meta-verifier-webapp.outputs.tags }}
|
||||
labels: ${{ steps.meta-verifier-webapp.outputs.labels }}
|
||||
build-args: |
|
||||
VITE_VERIFIER_HOST=demo-staging.tlsnotary.org
|
||||
VITE_VERIFIER_HOST=demo.tlsnotary.org
|
||||
VITE_SSL=true
|
||||
GIT_HASH=${{ github.sha }}
|
||||
|
||||
@@ -4,6 +4,7 @@ FROM node:20-alpine AS builder
|
||||
# Accept build arguments with defaults
|
||||
ARG VITE_VERIFIER_HOST=localhost:7047
|
||||
ARG VITE_SSL=false
|
||||
ARG GIT_HASH=local
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -17,6 +18,7 @@ COPY . .
|
||||
# Build with environment variables
|
||||
ENV VITE_VERIFIER_HOST=${VITE_VERIFIER_HOST}
|
||||
ENV VITE_SSL=${VITE_SSL}
|
||||
ENV GIT_HASH=${GIT_HASH}
|
||||
RUN npm run build
|
||||
|
||||
# Runtime stage
|
||||
|
||||
@@ -18,9 +18,10 @@ const PROXY_URL = `${SSL ? 'wss' : 'ws'}://${VERIFIER_HOST}/proxy?token=`;
|
||||
for (const plugin of plugins) {
|
||||
await build({
|
||||
configFile: false,
|
||||
publicDir: false, // Don't copy public assets into plugin output
|
||||
build: {
|
||||
lib: {
|
||||
entry: path.resolve(__dirname, `src/plugins/${plugin}.plugin.ts`),
|
||||
entry: path.resolve(__dirname, `plugins/${plugin}.plugin.ts`),
|
||||
formats: ['es'],
|
||||
fileName: () => `${plugin}.js`,
|
||||
},
|
||||
|
||||
@@ -9,6 +9,7 @@ services:
|
||||
- "7047:7047"
|
||||
environment:
|
||||
- RUST_LOG=info
|
||||
- GIT_HASH=${GIT_HASH:-dev}
|
||||
restart: unless-stopped
|
||||
|
||||
demo-static:
|
||||
@@ -17,6 +18,7 @@ services:
|
||||
args:
|
||||
VITE_VERIFIER_HOST: ${VITE_VERIFIER_HOST:-localhost:7047}
|
||||
VITE_SSL: ${VITE_SSL:-false}
|
||||
GIT_HASH: ${GIT_HASH:-dev}
|
||||
restart: unless-stopped
|
||||
|
||||
nginx:
|
||||
|
||||
@@ -39,6 +39,12 @@ server {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
location /info {
|
||||
proxy_pass http://verifier:7047;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
# Default: proxy to static demo server
|
||||
location / {
|
||||
proxy_pass http://demo-static:80;
|
||||
|
||||
@@ -24,19 +24,6 @@ const config = {
|
||||
],
|
||||
};
|
||||
|
||||
function getRelevantHeaderValues() {
|
||||
const [header] = useHeaders(headers => {
|
||||
return headers.filter(header => header.url.includes(`https://${api}/2023-05-23/users`));
|
||||
});
|
||||
|
||||
const authorization = header?.requestHeaders.find(header => header.name === 'Authorization')?.value;
|
||||
|
||||
const traceId = header?.requestHeaders.find(header => header.name === 'X-Amzn-Trace-Id')?.value;
|
||||
const user_id = traceId?.split('=')[1];
|
||||
|
||||
return { authorization, user_id };
|
||||
}
|
||||
|
||||
async function onClick() {
|
||||
const isRequestPending = useState('isRequestPending', false);
|
||||
|
||||
@@ -44,7 +31,14 @@ async function onClick() {
|
||||
|
||||
setState('isRequestPending', true);
|
||||
|
||||
const { authorization, user_id } = getRelevantHeaderValues();
|
||||
// Use cached values from state
|
||||
const authorization = useState('authorization', null);
|
||||
const user_id = useState('user_id', null);
|
||||
|
||||
if (!authorization || !user_id) {
|
||||
setState('isRequestPending', false);
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = {
|
||||
authorization: authorization,
|
||||
@@ -82,11 +76,32 @@ function minimizeUI() {
|
||||
}
|
||||
|
||||
function main() {
|
||||
const { authorization, user_id } = getRelevantHeaderValues();
|
||||
const header_has_necessary_values = authorization && user_id;
|
||||
|
||||
const isMinimized = useState('isMinimized', false);
|
||||
const isRequestPending = useState('isRequestPending', false);
|
||||
const authorization = useState('authorization', null);
|
||||
const user_id = useState('user_id', null);
|
||||
|
||||
// Only search for auth values if not already cached
|
||||
if (!authorization || !user_id) {
|
||||
const [header] = useHeaders(headers => {
|
||||
return headers.filter(header => header.url.includes(`https://${api}/2023-05-23/users`));
|
||||
});
|
||||
|
||||
const authValue = header?.requestHeaders.find(h => h.name === 'Authorization')?.value;
|
||||
const traceId = header?.requestHeaders.find(h => h.name === 'X-Amzn-Trace-Id')?.value;
|
||||
const userIdValue = traceId?.split('=')[1];
|
||||
|
||||
if (authValue && !authorization) {
|
||||
setState('authorization', authValue);
|
||||
console.log('Authorization found:', authValue);
|
||||
}
|
||||
if (userIdValue && !user_id) {
|
||||
setState('user_id', userIdValue);
|
||||
console.log('User ID found:', userIdValue);
|
||||
}
|
||||
}
|
||||
|
||||
const header_has_necessary_values = authorization && user_id;
|
||||
|
||||
useEffect(() => {
|
||||
openWindow(ui);
|
||||
@@ -33,12 +33,16 @@ async function onClick() {
|
||||
|
||||
setState('isRequestPending', true);
|
||||
|
||||
const [header] = useHeaders(headers => {
|
||||
return headers.filter(header => header.url.includes(`https://${api}`));
|
||||
});
|
||||
// Use cached authorization token from state
|
||||
const authToken = useState('authToken', null);
|
||||
|
||||
if (!authToken) {
|
||||
setState('isRequestPending', false);
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = {
|
||||
authorization: header.requestHeaders.find(header => header.name === 'Authorization')?.value,
|
||||
authorization: authToken,
|
||||
Host: api,
|
||||
'Accept-Encoding': 'identity',
|
||||
Connection: 'close',
|
||||
@@ -79,10 +83,23 @@ function minimizeUI() {
|
||||
}
|
||||
|
||||
function main() {
|
||||
const [header] = useHeaders(headers => headers.filter(h => h.url.includes(`https://${api}`)));
|
||||
|
||||
const isMinimized = useState('isMinimized', false);
|
||||
const isRequestPending = useState('isRequestPending', false);
|
||||
const authToken = useState('authToken', null);
|
||||
|
||||
|
||||
// Only search for auth token if not already cached
|
||||
if (!authToken) {
|
||||
const token = useHeaders(h => h.filter(x => x.url.startsWith(`https://${api}`)))
|
||||
.flatMap(h => h.requestHeaders)
|
||||
.find((h: { name: string; value?: string }) => h.name === 'Authorization')
|
||||
?.value;
|
||||
|
||||
if (token) {
|
||||
setState('authToken', token);
|
||||
console.log('Auth Token found:', token);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
openWindow(ui);
|
||||
@@ -172,16 +189,16 @@ function main() {
|
||||
marginBottom: '16px',
|
||||
padding: '12px',
|
||||
borderRadius: '6px',
|
||||
backgroundColor: header ? '#d4edda' : '#f8d7da',
|
||||
color: header ? '#155724' : '#721c24',
|
||||
border: `1px solid ${header ? '#c3e6cb' : '#f5c6cb'}`,
|
||||
backgroundColor: authToken ? '#d4edda' : '#f8d7da',
|
||||
color: authToken ? '#155724' : '#721c24',
|
||||
border: `1px solid ${authToken ? '#c3e6cb' : '#f5c6cb'}`,
|
||||
fontWeight: '500',
|
||||
},
|
||||
}, [
|
||||
header ? '✓ Api token detected' : '⚠ No API token detected'
|
||||
authToken ? '✓ Api token detected' : '⚠ No API token detected'
|
||||
]),
|
||||
|
||||
header ? (
|
||||
authToken ? (
|
||||
button({
|
||||
style: {
|
||||
width: '100%',
|
||||
@@ -194,7 +211,7 @@ function main() {
|
||||
fontSize: '15px',
|
||||
transition: 'all 0.2s ease',
|
||||
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
|
||||
opacity: isRequestPending ? 0.5 : 1,
|
||||
opacity: isRequestPending ? '0.5' : '1',
|
||||
cursor: isRequestPending ? 'not-allowed' : 'pointer',
|
||||
},
|
||||
onclick: 'onClick',
|
||||
@@ -33,13 +33,17 @@ async function onClick() {
|
||||
if (isRequestPending) return;
|
||||
|
||||
setState('isRequestPending', true);
|
||||
const [header] = useHeaders((headers: any[]) => {
|
||||
console.log('Intercepted headers:', headers);
|
||||
return headers.filter(header => header.url.includes(`https://${host}`));
|
||||
});
|
||||
|
||||
// Use cached cookie from state
|
||||
const cachedCookie = useState('cookie', null);
|
||||
|
||||
if (!cachedCookie) {
|
||||
setState('isRequestPending', false);
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = {
|
||||
'cookie': header.requestHeaders.find((header: any) => header.name === 'Cookie')?.value,
|
||||
'cookie': cachedCookie,
|
||||
Host: host,
|
||||
'Accept-Encoding': 'identity',
|
||||
Connection: 'close',
|
||||
@@ -87,13 +91,24 @@ function minimizeUI() {
|
||||
}
|
||||
|
||||
function main() {
|
||||
const [header] = useHeaders((headers: any[]) =>
|
||||
headers.filter(header => header.url.includes(`https://${host}${ui_path}`))
|
||||
);
|
||||
|
||||
const hasNecessaryHeader = header?.requestHeaders.some((h: any) => h.name === 'Cookie');
|
||||
const isMinimized = useState('isMinimized', false);
|
||||
const isRequestPending = useState('isRequestPending', false);
|
||||
const cachedCookie = useState('cookie', null);
|
||||
|
||||
// Only search for cookie if not already cached
|
||||
if (!cachedCookie) {
|
||||
const [header] = useHeaders((headers: any[]) =>
|
||||
headers.filter(h => h.url.includes(`https://${host}`))
|
||||
);
|
||||
|
||||
if (header) {
|
||||
const cookie = header.requestHeaders.find((h: any) => h.name === 'Cookie')?.value;
|
||||
if (cookie) {
|
||||
setState('cookie', cookie);
|
||||
console.log('Cookie found');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
openWindow(`https://${host}${ui_path}`);
|
||||
@@ -200,15 +215,15 @@ function main() {
|
||||
marginBottom: '16px',
|
||||
padding: '12px',
|
||||
borderRadius: '6px',
|
||||
backgroundColor: header ? '#d4edda' : '#f8d7da',
|
||||
color: header ? '#155724' : '#721c24',
|
||||
border: `1px solid ${header ? '#c3e6cb' : '#f5c6cb'}`,
|
||||
backgroundColor: cachedCookie ? '#d4edda' : '#f8d7da',
|
||||
color: cachedCookie ? '#155724' : '#721c24',
|
||||
border: `1px solid ${cachedCookie ? '#c3e6cb' : '#f5c6cb'}`,
|
||||
fontWeight: '500',
|
||||
},
|
||||
},
|
||||
[hasNecessaryHeader ? '✓ Cookie detected' : '⚠ No Cookie detected']
|
||||
[cachedCookie ? '✓ Cookie detected' : '⚠ No Cookie detected']
|
||||
),
|
||||
hasNecessaryHeader
|
||||
cachedCookie
|
||||
? button(
|
||||
{
|
||||
style: {
|
||||
@@ -45,16 +45,23 @@ async function onClick() {
|
||||
|
||||
setState('isRequestPending', true);
|
||||
|
||||
const [header] = useHeaders((headers: any[]) => {
|
||||
return headers.filter(header => header.url.includes('https://api.x.com/1.1/account/settings.json'));
|
||||
});
|
||||
// Use cached values from state
|
||||
const cachedCookie = useState('cookie', null);
|
||||
const cachedCsrfToken = useState('x-csrf-token', null);
|
||||
const cachedTransactionId = useState('x-client-transaction-id', null);
|
||||
const cachedAuthorization = useState('authorization', null);
|
||||
|
||||
if (!cachedCookie || !cachedCsrfToken || !cachedAuthorization) {
|
||||
setState('isRequestPending', false);
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = {
|
||||
'cookie': header.requestHeaders.find((header: any) => header.name === 'Cookie')?.value,
|
||||
'x-csrf-token': header.requestHeaders.find((header: any) => header.name === 'x-csrf-token')?.value,
|
||||
'x-client-transaction-id': header.requestHeaders.find((header: any) => header.name === 'x-client-transaction-id')?.value,
|
||||
'cookie': cachedCookie,
|
||||
'x-csrf-token': cachedCsrfToken,
|
||||
...(cachedTransactionId ? { 'x-client-transaction-id': cachedTransactionId } : {}),
|
||||
Host: 'api.x.com',
|
||||
authorization: header.requestHeaders.find((header: any) => header.name === 'authorization')?.value,
|
||||
authorization: cachedAuthorization,
|
||||
'Accept-Encoding': 'identity',
|
||||
Connection: 'close',
|
||||
};
|
||||
@@ -63,7 +70,7 @@ async function onClick() {
|
||||
{
|
||||
url: 'https://api.x.com/1.1/account/settings.json',
|
||||
method: 'GET',
|
||||
headers: headers,
|
||||
headers: headers as unknown as Record<string, string>,
|
||||
},
|
||||
{
|
||||
verifierUrl: VERIFIER_URL,
|
||||
@@ -107,11 +114,45 @@ function minimizeUI() {
|
||||
// MAIN UI FUNCTION
|
||||
// =============================================================================
|
||||
function main() {
|
||||
const [header] = useHeaders((headers: any[]) =>
|
||||
headers.filter(header => header.url.includes('https://api.x.com/1.1/account/settings.json'))
|
||||
);
|
||||
const isMinimized = useState('isMinimized', false);
|
||||
const isRequestPending = useState('isRequestPending', false);
|
||||
const cachedCookie = useState('cookie', null);
|
||||
const cachedCsrfToken = useState('x-csrf-token', null);
|
||||
const cachedTransactionId = useState('x-client-transaction-id', null);
|
||||
const cachedAuthorization = useState('authorization', null);
|
||||
|
||||
// Only search for header values if not already cached
|
||||
if (!cachedCookie || !cachedCsrfToken || !cachedAuthorization) {
|
||||
const [header] = useHeaders((headers: any[]) =>
|
||||
headers.filter(h => h.url.includes('https://api.x.com/1.1/account/settings.json'))
|
||||
);
|
||||
|
||||
if (header) {
|
||||
const cookie = header.requestHeaders.find((h: any) => h.name === 'Cookie')?.value;
|
||||
const csrfToken = header.requestHeaders.find((h: any) => h.name === 'x-csrf-token')?.value;
|
||||
const transactionId = header.requestHeaders.find((h: any) => h.name === 'x-client-transaction-id')?.value;
|
||||
const authorization = header.requestHeaders.find((h: any) => h.name === 'authorization')?.value;
|
||||
|
||||
if (cookie && !cachedCookie) {
|
||||
setState('cookie', cookie);
|
||||
console.log('Cookie found');
|
||||
}
|
||||
if (csrfToken && !cachedCsrfToken) {
|
||||
setState('x-csrf-token', csrfToken);
|
||||
console.log('CSRF token found');
|
||||
}
|
||||
if (transactionId && !cachedTransactionId) {
|
||||
setState('x-client-transaction-id', transactionId);
|
||||
console.log('Transaction ID found');
|
||||
}
|
||||
if (authorization && !cachedAuthorization) {
|
||||
setState('authorization', authorization);
|
||||
console.log('Authorization found');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const header = cachedCookie && cachedCsrfToken && cachedAuthorization;
|
||||
|
||||
useEffect(() => {
|
||||
openWindow('https://x.com');
|
||||
@@ -240,7 +281,7 @@ function main() {
|
||||
fontSize: '15px',
|
||||
transition: 'all 0.2s ease',
|
||||
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
|
||||
opacity: isRequestPending ? 0.5 : 1,
|
||||
opacity: isRequestPending ? '0.5' : '1',
|
||||
cursor: isRequestPending ? 'not-allowed' : 'pointer',
|
||||
},
|
||||
onclick: 'onClick',
|
||||
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
2
packages/demo/public/robots.txt
Normal file
2
packages/demo/public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
@@ -290,7 +290,7 @@ export function App() {
|
||||
>
|
||||
View source on GitHub
|
||||
</a>
|
||||
<span className="footer-version">v{__GIT_COMMIT_HASH__}</span>
|
||||
<span className="footer-version">{__GIT_COMMIT_HASH__}</span>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -71,7 +71,7 @@ export function StatusBar({
|
||||
{!extensionOk && (
|
||||
<div>
|
||||
TLSNotary extension not detected.{' '}
|
||||
<a href="chrome://extensions/" target="_blank" rel="noopener noreferrer">
|
||||
<a href="https://chromewebstore.google.com/detail/tlsnotary/gnoglgpcamodhflknhmafmjdahcejcgg?authuser=2&hl=en" target="_blank" rel="noopener noreferrer">
|
||||
Install extension
|
||||
</a>
|
||||
{' '}then <strong>refresh this page</strong>.
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"src/plugins/**/*.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
// Get git commit hash at build time
|
||||
const getGitCommitHash = () => {
|
||||
try {
|
||||
return execSync('git rev-parse --short HEAD').toString().trim();
|
||||
} catch {
|
||||
return 'unknown';
|
||||
}
|
||||
};
|
||||
// Get git commit hash from GIT_HASH env var (set by CI/Docker) or fallback to 'local'
|
||||
const gitHash = process.env.GIT_HASH || 'local';
|
||||
|
||||
export default defineConfig({
|
||||
define: {
|
||||
__GIT_COMMIT_HASH__: JSON.stringify(getGitCommitHash()),
|
||||
__GIT_COMMIT_HASH__: JSON.stringify(gitHash),
|
||||
},
|
||||
plugins: [react()],
|
||||
build: {
|
||||
|
||||
@@ -34,6 +34,10 @@ FROM debian:bookworm-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Accept build argument for git hash and set as environment variable
|
||||
ARG GIT_HASH=local
|
||||
ENV GIT_HASH=${GIT_HASH}
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
ca-certificates \
|
||||
|
||||
Reference in New Issue
Block a user