mirror of
https://github.com/tlsnotary/tlsn-extension.git
synced 2026-01-22 13:38:07 -05:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
571631d78c | ||
|
|
99a466db02 |
1
.github/workflows/demo.yml
vendored
1
.github/workflows/demo.yml
vendored
@@ -105,4 +105,3 @@ jobs:
|
||||
build-args: |
|
||||
VITE_VERIFIER_HOST=demo-staging.tlsnotary.org
|
||||
VITE_SSL=true
|
||||
GIT_HASH=${{ github.sha }}
|
||||
|
||||
@@ -4,7 +4,6 @@ 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
|
||||
|
||||
@@ -18,7 +17,6 @@ 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
|
||||
|
||||
@@ -5,7 +5,7 @@ import fs from 'fs';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const plugins = ['twitter', 'swissbank', 'spotify', 'duolingo'];
|
||||
const plugins = ['twitter', 'swissbank', 'spotify', 'duolingo', 'discord_dm', 'discord_profile'];
|
||||
|
||||
// Build URLs from environment variables (matching config.ts pattern)
|
||||
const VERIFIER_HOST = process.env.VITE_VERIFIER_HOST || 'localhost:7047';
|
||||
|
||||
@@ -9,7 +9,6 @@ services:
|
||||
- "7047:7047"
|
||||
environment:
|
||||
- RUST_LOG=info
|
||||
- GIT_HASH=${GIT_HASH:-dev}
|
||||
restart: unless-stopped
|
||||
|
||||
demo-static:
|
||||
@@ -18,7 +17,6 @@ services:
|
||||
args:
|
||||
VITE_VERIFIER_HOST: ${VITE_VERIFIER_HOST:-localhost:7047}
|
||||
VITE_SSL: ${VITE_SSL:-false}
|
||||
GIT_HASH: ${GIT_HASH:-dev}
|
||||
restart: unless-stopped
|
||||
|
||||
nginx:
|
||||
|
||||
@@ -290,7 +290,7 @@ export function App() {
|
||||
>
|
||||
View source on GitHub
|
||||
</a>
|
||||
<span className="footer-version">{__GIT_COMMIT_HASH__}</span>
|
||||
<span className="footer-version">v{__GIT_COMMIT_HASH__}</span>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -37,4 +37,22 @@ export const plugins: Record<string, Plugin> = {
|
||||
return json.results[json.results.length - 1].value;
|
||||
},
|
||||
},
|
||||
// discord_dm: {
|
||||
// name: 'Discord DM',
|
||||
// description: 'Prove your Discord direct messages',
|
||||
// logo: '💬',
|
||||
// file: '/plugins/discord_dm.js',
|
||||
// parseResult: (json) => {
|
||||
// return json.results[json.results.length - 1].value;
|
||||
// },
|
||||
// },
|
||||
discord_profile: {
|
||||
name: 'Discord Profile',
|
||||
description: 'Prove your Discord profile information',
|
||||
logo: '💬',
|
||||
file: '/plugins/discord_profile.js',
|
||||
parseResult: (json) => {
|
||||
return json.results[json.results.length - 1].value;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
342
packages/demo/src/plugins/discord_dm.plugin.ts
Normal file
342
packages/demo/src/plugins/discord_dm.plugin.ts
Normal file
@@ -0,0 +1,342 @@
|
||||
/// <reference types="@tlsn/plugin-sdk/src/globals" />
|
||||
|
||||
// @ts-ignore - These will be replaced at build time by Vite's define option
|
||||
const VERIFIER_URL = VITE_VERIFIER_URL;
|
||||
// @ts-ignore
|
||||
const PROXY_URL_BASE = VITE_PROXY_URL;
|
||||
|
||||
const api = 'discord.com';
|
||||
const ui = 'https://discord.com/channels/@me';
|
||||
|
||||
const config = {
|
||||
name: 'Discord DM Plugin',
|
||||
description: 'This plugin will prove your Discord direct messages.',
|
||||
requests: [
|
||||
{
|
||||
method: 'GET',
|
||||
host: 'discord.com',
|
||||
pathname: '/api/v9/users/@me/channels',
|
||||
verifierUrl: VERIFIER_URL,
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
host: 'discord.com',
|
||||
pathname: '/api/v9/channels/*/messages',
|
||||
verifierUrl: VERIFIER_URL,
|
||||
},
|
||||
],
|
||||
urls: [
|
||||
'https://discord.com/*',
|
||||
],
|
||||
};
|
||||
|
||||
function getRelevantHeaderValues() {
|
||||
const [header] = useHeaders(headers => {
|
||||
return headers.filter(header =>
|
||||
header.url.includes(`https://${api}/api/v9/users/@me`) ||
|
||||
header.url.includes(`https://${api}/api/v9/channels`)
|
||||
);
|
||||
});
|
||||
|
||||
const authorization = header?.requestHeaders.find(header => header.name === 'authorization')?.value;
|
||||
|
||||
return { authorization };
|
||||
}
|
||||
|
||||
async function fetchDMs() {
|
||||
const { authorization } = getRelevantHeaderValues();
|
||||
|
||||
if (!authorization) return [];
|
||||
|
||||
try {
|
||||
const headers = {
|
||||
authorization: authorization,
|
||||
Host: api,
|
||||
'Accept-Encoding': 'identity',
|
||||
Connection: 'close',
|
||||
};
|
||||
|
||||
const response = await fetch(`https://${api}/api/v9/users/@me/channels`, {
|
||||
method: 'GET',
|
||||
headers: headers,
|
||||
});
|
||||
|
||||
const channels = await response.json();
|
||||
|
||||
// Filter only DM channels (type 1)
|
||||
return channels.filter((channel: any) => channel.type === 1).map((channel: any) => ({
|
||||
id: channel.id,
|
||||
name: channel.recipients?.[0]?.username || 'Unknown User',
|
||||
avatar: channel.recipients?.[0]?.avatar,
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('Error fetching DMs:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function onClick() {
|
||||
const isRequestPending = useState('isRequestPending', false);
|
||||
const selectedDMId = useState('selectedDMId', '');
|
||||
|
||||
if (isRequestPending || !selectedDMId) return;
|
||||
|
||||
setState('isRequestPending', true);
|
||||
|
||||
const { authorization } = getRelevantHeaderValues();
|
||||
|
||||
const headers = {
|
||||
authorization: authorization,
|
||||
Host: api,
|
||||
'Accept-Encoding': 'identity',
|
||||
Connection: 'close',
|
||||
};
|
||||
|
||||
const resp = await prove(
|
||||
{
|
||||
url: `https://${api}/api/v9/channels/${selectedDMId}/messages?limit=50`,
|
||||
method: 'GET',
|
||||
headers: headers,
|
||||
},
|
||||
{
|
||||
verifierUrl: VERIFIER_URL,
|
||||
proxyUrl: PROXY_URL_BASE + api,
|
||||
maxRecvData: 8000,
|
||||
maxSentData: 2000,
|
||||
handlers: [
|
||||
{ type: 'SENT', part: 'START_LINE', action: 'REVEAL' },
|
||||
{ type: 'RECV', part: 'BODY', action: 'REVEAL', params: { type: 'json', path: '[*].content' } },
|
||||
{ type: 'RECV', part: 'BODY', action: 'REVEAL', params: { type: 'json', path: '[*].author.username' } },
|
||||
{ type: 'RECV', part: 'BODY', action: 'REVEAL', params: { type: 'json', path: '[*].timestamp' } },
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
setState('isRequestPending', false);
|
||||
done(JSON.stringify(resp));
|
||||
}
|
||||
|
||||
function selectDM(dmId: string) {
|
||||
setState('selectedDMId', dmId);
|
||||
}
|
||||
|
||||
function expandUI() {
|
||||
setState('isMinimized', false);
|
||||
}
|
||||
|
||||
function minimizeUI() {
|
||||
setState('isMinimized', true);
|
||||
}
|
||||
|
||||
function main() {
|
||||
const { authorization } = getRelevantHeaderValues();
|
||||
const header_has_necessary_values = !!authorization;
|
||||
|
||||
const isMinimized = useState('isMinimized', false);
|
||||
const isRequestPending = useState('isRequestPending', false);
|
||||
const selectedDMId = useState('selectedDMId', '');
|
||||
const dmList = useState('dmList', []);
|
||||
|
||||
useEffect(() => {
|
||||
openWindow(ui);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (header_has_necessary_values && dmList.length === 0) {
|
||||
fetchDMs().then(dms => setState('dmList', dms));
|
||||
}
|
||||
}, [header_has_necessary_values]);
|
||||
|
||||
if (isMinimized) {
|
||||
return div({
|
||||
style: {
|
||||
position: 'fixed',
|
||||
bottom: '20px',
|
||||
right: '20px',
|
||||
width: '60px',
|
||||
height: '60px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: '#5865F2',
|
||||
boxShadow: '0 4px 8px rgba(0,0,0,0.3)',
|
||||
zIndex: '999999',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.3s ease',
|
||||
fontSize: '24px',
|
||||
color: 'white',
|
||||
},
|
||||
onclick: 'expandUI',
|
||||
}, ['💬']);
|
||||
}
|
||||
|
||||
return div({
|
||||
style: {
|
||||
position: 'fixed',
|
||||
bottom: '0',
|
||||
right: '8px',
|
||||
width: '320px',
|
||||
borderRadius: '8px 8px 0 0',
|
||||
backgroundColor: 'white',
|
||||
boxShadow: '0 -2px 10px rgba(0,0,0,0.1)',
|
||||
zIndex: '999999',
|
||||
fontSize: '14px',
|
||||
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
}, [
|
||||
div({
|
||||
style: {
|
||||
background: 'linear-gradient(135deg, #5865F2 0%, #4752C4 100%)',
|
||||
padding: '12px 16px',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
color: 'white',
|
||||
}
|
||||
}, [
|
||||
div({
|
||||
style: {
|
||||
fontWeight: '600',
|
||||
fontSize: '16px',
|
||||
}
|
||||
}, ['Discord DM Proof']),
|
||||
button({
|
||||
style: {
|
||||
background: 'transparent',
|
||||
border: 'none',
|
||||
color: 'white',
|
||||
fontSize: '20px',
|
||||
cursor: 'pointer',
|
||||
padding: '0',
|
||||
width: '24px',
|
||||
height: '24px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
onclick: 'minimizeUI',
|
||||
}, ['−'])
|
||||
]),
|
||||
|
||||
div({
|
||||
style: {
|
||||
padding: '20px',
|
||||
backgroundColor: '#f8f9fa',
|
||||
}
|
||||
}, [
|
||||
// Step 1: Login Status
|
||||
div({
|
||||
style: {
|
||||
marginBottom: '16px',
|
||||
padding: '12px',
|
||||
borderRadius: '6px',
|
||||
backgroundColor: header_has_necessary_values ? '#d4edda' : '#f8d7da',
|
||||
color: header_has_necessary_values ? '#155724' : '#721c24',
|
||||
border: `1px solid ${header_has_necessary_values ? '#c3e6cb' : '#f5c6cb'}`,
|
||||
fontWeight: '500',
|
||||
},
|
||||
}, [
|
||||
header_has_necessary_values ? '✓ Discord token detected' : '⚠ No Discord token detected'
|
||||
]),
|
||||
|
||||
// Step 2: DM Selection
|
||||
header_has_necessary_values && dmList.length > 0 ? (
|
||||
div({
|
||||
style: {
|
||||
marginBottom: '16px',
|
||||
}
|
||||
}, [
|
||||
div({
|
||||
style: {
|
||||
marginBottom: '8px',
|
||||
fontWeight: '600',
|
||||
color: '#333',
|
||||
}
|
||||
}, ['Select a DM:']),
|
||||
div({
|
||||
style: {
|
||||
maxHeight: '200px',
|
||||
overflowY: 'auto',
|
||||
border: '1px solid #ddd',
|
||||
borderRadius: '6px',
|
||||
backgroundColor: 'white',
|
||||
}
|
||||
}, dmList.map((dm: any) =>
|
||||
div({
|
||||
style: {
|
||||
padding: '10px 12px',
|
||||
cursor: 'pointer',
|
||||
borderBottom: '1px solid #f0f0f0',
|
||||
backgroundColor: selectedDMId === dm.id ? '#e3f2fd' : 'transparent',
|
||||
transition: 'background-color 0.2s',
|
||||
},
|
||||
onclick: () => selectDM(dm.id),
|
||||
}, [
|
||||
div({
|
||||
style: {
|
||||
fontWeight: selectedDMId === dm.id ? '600' : '400',
|
||||
color: '#333',
|
||||
}
|
||||
}, [dm.name])
|
||||
])
|
||||
))
|
||||
])
|
||||
) : null,
|
||||
|
||||
// Step 3: Notarize Button
|
||||
header_has_necessary_values && selectedDMId ? (
|
||||
button({
|
||||
style: {
|
||||
width: '100%',
|
||||
padding: '12px 24px',
|
||||
borderRadius: '6px',
|
||||
border: 'none',
|
||||
background: 'linear-gradient(135deg, #5865F2 0%, #4752C4 100%)',
|
||||
color: 'white',
|
||||
fontWeight: '600',
|
||||
fontSize: '15px',
|
||||
cursor: isRequestPending ? 'not-allowed' : 'pointer',
|
||||
transition: 'all 0.2s ease',
|
||||
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
|
||||
opacity: isRequestPending ? 0.5 : 1,
|
||||
},
|
||||
onclick: 'onClick',
|
||||
}, [isRequestPending ? 'Generating Proof...' : 'Generate Proof'])
|
||||
) : header_has_necessary_values && dmList.length === 0 ? (
|
||||
div({
|
||||
style: {
|
||||
textAlign: 'center',
|
||||
color: '#666',
|
||||
padding: '12px',
|
||||
backgroundColor: '#fff3cd',
|
||||
borderRadius: '6px',
|
||||
border: '1px solid #ffeaa7',
|
||||
}
|
||||
}, ['Loading DMs...'])
|
||||
) : !header_has_necessary_values ? (
|
||||
div({
|
||||
style: {
|
||||
textAlign: 'center',
|
||||
color: '#666',
|
||||
padding: '12px',
|
||||
backgroundColor: '#fff3cd',
|
||||
borderRadius: '6px',
|
||||
border: '1px solid #ffeaa7',
|
||||
}
|
||||
}, ['Please login to Discord to continue'])
|
||||
) : null
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
export default {
|
||||
main,
|
||||
onClick,
|
||||
expandUI,
|
||||
minimizeUI,
|
||||
fetchDMs,
|
||||
selectDM,
|
||||
config,
|
||||
};
|
||||
232
packages/demo/src/plugins/discord_profile.plugin.ts
Normal file
232
packages/demo/src/plugins/discord_profile.plugin.ts
Normal file
@@ -0,0 +1,232 @@
|
||||
/// <reference types="@tlsn/plugin-sdk/src/globals" />
|
||||
|
||||
// @ts-ignore - These will be replaced at build time by Vite's define option
|
||||
const VERIFIER_URL = VITE_VERIFIER_URL;
|
||||
// @ts-ignore
|
||||
const PROXY_URL_BASE = VITE_PROXY_URL;
|
||||
const api = 'discord.com';
|
||||
const ui = `https://${api}/channels/@me`;
|
||||
|
||||
const config = {
|
||||
name: 'Discord Profile Plugin',
|
||||
description: 'This plugin will prove your Discord username and ID.',
|
||||
requests: [
|
||||
{
|
||||
method: 'GET',
|
||||
host: api,
|
||||
pathname: '/api/v9/users/@me',
|
||||
verifierUrl: VERIFIER_URL,
|
||||
},
|
||||
],
|
||||
urls: [
|
||||
`https://${api}/*`,
|
||||
],
|
||||
};
|
||||
|
||||
function getRelevantHeaderValues() {
|
||||
const [header] = useHeaders(headers => {
|
||||
// console.log('All captured headers:', headers);
|
||||
// Find the first header that contains an 'authorization' request header, regardless of URL
|
||||
return [headers.find(h =>
|
||||
h.requestHeaders.some(rh => rh.name === 'Authorization')
|
||||
)];
|
||||
});
|
||||
|
||||
const authorization = header?.requestHeaders.find(h => h.name === 'Authorization')?.value;
|
||||
return { authorization };
|
||||
}
|
||||
|
||||
async function onClick() {
|
||||
const isRequestPending = useState('isRequestPending', false);
|
||||
|
||||
if (isRequestPending) return;
|
||||
|
||||
setState('isRequestPending', true);
|
||||
|
||||
const { authorization } = getRelevantHeaderValues();
|
||||
|
||||
const headers = {
|
||||
authorization: authorization,
|
||||
Host: api,
|
||||
'Accept-Encoding': 'identity',
|
||||
Connection: 'close',
|
||||
};
|
||||
|
||||
const resp = await prove(
|
||||
{
|
||||
url: `https://${api}/api/v9/users/@me`,
|
||||
method: 'GET',
|
||||
headers: headers,
|
||||
},
|
||||
{
|
||||
verifierUrl: VERIFIER_URL,
|
||||
proxyUrl: PROXY_URL_BASE + api,
|
||||
maxRecvData: 2000,
|
||||
maxSentData: 1000,
|
||||
handlers: [
|
||||
{ type: 'SENT', part: 'START_LINE', action: 'REVEAL' },
|
||||
{ type: 'RECV', part: 'BODY', action: 'REVEAL', params: { type: 'json', path: 'username' } },
|
||||
{ type: 'RECV', part: 'BODY', action: 'REVEAL', params: { type: 'json', path: 'id' } },
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
done(JSON.stringify(resp));
|
||||
}
|
||||
|
||||
function expandUI() {
|
||||
setState('isMinimized', false);
|
||||
}
|
||||
|
||||
function minimizeUI() {
|
||||
setState('isMinimized', true);
|
||||
}
|
||||
|
||||
function main() {
|
||||
const { authorization } = getRelevantHeaderValues();
|
||||
|
||||
console.log('🚀🚀🚀🚀🚀🚀🚀 Authorization Header:', authorization);
|
||||
|
||||
const header_has_necessary_values = !!authorization;
|
||||
|
||||
const isMinimized = useState('isMinimized', false);
|
||||
const isRequestPending = useState('isRequestPending', false);
|
||||
|
||||
useEffect(() => {
|
||||
openWindow(ui);
|
||||
}, []);
|
||||
|
||||
if (isMinimized) {
|
||||
return div({
|
||||
style: {
|
||||
position: 'fixed',
|
||||
bottom: '20px',
|
||||
right: '20px',
|
||||
width: '60px',
|
||||
height: '60px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: '#5865F2',
|
||||
boxShadow: '0 4px 8px rgba(0,0,0,0.3)',
|
||||
zIndex: '999999',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.3s ease',
|
||||
fontSize: '24px',
|
||||
color: 'white',
|
||||
},
|
||||
onclick: 'expandUI',
|
||||
}, ['💬']);
|
||||
}
|
||||
|
||||
return div({
|
||||
style: {
|
||||
position: 'fixed',
|
||||
bottom: '0',
|
||||
right: '8px',
|
||||
width: '320px',
|
||||
borderRadius: '8px 8px 0 0',
|
||||
backgroundColor: 'white',
|
||||
boxShadow: '0 -2px 10px rgba(0,0,0,0.1)',
|
||||
zIndex: '999999',
|
||||
fontSize: '14px',
|
||||
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
}, [
|
||||
div({
|
||||
style: {
|
||||
background: 'linear-gradient(135deg, #5865F2 0%, #4752C4 100%)',
|
||||
padding: '12px 16px',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
color: 'white',
|
||||
}
|
||||
}, [
|
||||
div({
|
||||
style: {
|
||||
fontWeight: '600',
|
||||
fontSize: '16px',
|
||||
}
|
||||
}, ['Discord Profile Proof']),
|
||||
button({
|
||||
style: {
|
||||
background: 'transparent',
|
||||
border: 'none',
|
||||
color: 'white',
|
||||
fontSize: '20px',
|
||||
cursor: 'pointer',
|
||||
padding: '0',
|
||||
width: '24px',
|
||||
height: '24px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
onclick: 'minimizeUI',
|
||||
}, ['−'])
|
||||
]),
|
||||
|
||||
div({
|
||||
style: {
|
||||
padding: '20px',
|
||||
backgroundColor: '#f8f9fa',
|
||||
}
|
||||
}, [
|
||||
div({
|
||||
style: {
|
||||
marginBottom: '16px',
|
||||
padding: '12px',
|
||||
borderRadius: '6px',
|
||||
backgroundColor: header_has_necessary_values ? '#d4edda' : '#f8d7da',
|
||||
color: header_has_necessary_values ? '#155724' : '#721c24',
|
||||
border: `1px solid ${header_has_necessary_values ? '#c3e6cb' : '#f5c6cb'}`,
|
||||
fontWeight: '500',
|
||||
},
|
||||
}, [
|
||||
header_has_necessary_values ? '✓ Discord token detected' : '⚠ Please login to Discord'
|
||||
]),
|
||||
|
||||
header_has_necessary_values ? (
|
||||
button({
|
||||
style: {
|
||||
width: '100%',
|
||||
padding: '12px 24px',
|
||||
borderRadius: '6px',
|
||||
border: 'none',
|
||||
background: 'linear-gradient(135deg, #5865F2 0%, #4752C4 100%)',
|
||||
color: 'white',
|
||||
fontWeight: '600',
|
||||
fontSize: '15px',
|
||||
cursor: isRequestPending ? 'not-allowed' : 'pointer',
|
||||
transition: 'all 0.2s ease',
|
||||
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
|
||||
opacity: isRequestPending ? 0.5 : 1,
|
||||
},
|
||||
onclick: 'onClick',
|
||||
}, [isRequestPending ? 'Generating Proof...' : 'Generate Proof'])
|
||||
) : (
|
||||
div({
|
||||
style: {
|
||||
textAlign: 'center',
|
||||
color: '#666',
|
||||
padding: '12px',
|
||||
backgroundColor: '#fff3cd',
|
||||
borderRadius: '6px',
|
||||
border: '1px solid #ffeaa7',
|
||||
}
|
||||
}, ['Please login to Discord to continue'])
|
||||
)
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
export default {
|
||||
main,
|
||||
onClick,
|
||||
expandUI,
|
||||
minimizeUI,
|
||||
config,
|
||||
};
|
||||
@@ -33,16 +33,12 @@ async function onClick() {
|
||||
|
||||
setState('isRequestPending', true);
|
||||
|
||||
// Use cached authorization token from state
|
||||
const authToken = useState('authToken', null);
|
||||
|
||||
if (!authToken) {
|
||||
setState('isRequestPending', false);
|
||||
return;
|
||||
}
|
||||
const [header] = useHeaders(headers => {
|
||||
return headers.filter(header => header.url.includes(`https://${api}`));
|
||||
});
|
||||
|
||||
const headers = {
|
||||
authorization: authToken,
|
||||
authorization: header.requestHeaders.find(header => header.name === 'Authorization')?.value,
|
||||
Host: api,
|
||||
'Accept-Encoding': 'identity',
|
||||
Connection: 'close',
|
||||
@@ -83,23 +79,10 @@ 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);
|
||||
@@ -189,16 +172,16 @@ function main() {
|
||||
marginBottom: '16px',
|
||||
padding: '12px',
|
||||
borderRadius: '6px',
|
||||
backgroundColor: authToken ? '#d4edda' : '#f8d7da',
|
||||
color: authToken ? '#155724' : '#721c24',
|
||||
border: `1px solid ${authToken ? '#c3e6cb' : '#f5c6cb'}`,
|
||||
backgroundColor: header ? '#d4edda' : '#f8d7da',
|
||||
color: header ? '#155724' : '#721c24',
|
||||
border: `1px solid ${header ? '#c3e6cb' : '#f5c6cb'}`,
|
||||
fontWeight: '500',
|
||||
},
|
||||
}, [
|
||||
authToken ? '✓ Api token detected' : '⚠ No API token detected'
|
||||
header ? '✓ Api token detected' : '⚠ No API token detected'
|
||||
]),
|
||||
|
||||
authToken ? (
|
||||
header ? (
|
||||
button({
|
||||
style: {
|
||||
width: '100%',
|
||||
@@ -211,7 +194,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',
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
// Get git commit hash from GIT_HASH env var (set by CI/Docker) or fallback to 'local'
|
||||
const gitHash = process.env.GIT_HASH || 'local';
|
||||
// Get git commit hash at build time
|
||||
const getGitCommitHash = () => {
|
||||
try {
|
||||
return execSync('git rev-parse --short HEAD').toString().trim();
|
||||
} catch {
|
||||
return 'unknown';
|
||||
}
|
||||
};
|
||||
|
||||
export default defineConfig({
|
||||
define: {
|
||||
__GIT_COMMIT_HASH__: JSON.stringify(gitHash),
|
||||
__GIT_COMMIT_HASH__: JSON.stringify(getGitCommitHash()),
|
||||
},
|
||||
plugins: [react()],
|
||||
build: {
|
||||
|
||||
@@ -158,7 +158,7 @@ function makeUseHeaders(
|
||||
|
||||
// Validate that filterFn returned an array
|
||||
if (result === undefined) {
|
||||
throw new Error(`useHeaders: filter function returned undefined. expect an erray`);
|
||||
throw new Error(`useHeaders: filter function returned undefined. expect an array`);
|
||||
}
|
||||
if (!Array.isArray(result)) {
|
||||
throw new Error(`useHeaders: filter function must return an array, got ${typeof result}. `);
|
||||
|
||||
Reference in New Issue
Block a user