Refactor getDocumentValidation
This commit is contained in:
parent
ec9fe0f62c
commit
85fe8cc251
@ -1,179 +1,152 @@
|
|||||||
function randomHex32(): string {
|
import { ProcessState } from '../../../pkg/sdk_client';
|
||||||
return Array.from(crypto.getRandomValues(new Uint8Array(32)))
|
import Services from '../../services/service';
|
||||||
.map(b => b.toString(16).padStart(2, '0'))
|
|
||||||
.join('');
|
interface State {
|
||||||
|
file: File | null;
|
||||||
|
fileHash: string | null;
|
||||||
|
certificate: ProcessState | null;
|
||||||
|
commitmentHashes: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDocumentValidation(container: HTMLElement) {
|
export function getDocumentValidation(container: HTMLElement) {
|
||||||
container.innerHTML = ''; // clear previous content
|
const state: State = {
|
||||||
container.style.display = 'block';
|
file: null,
|
||||||
|
fileHash: null,
|
||||||
const state = {
|
certificate: null,
|
||||||
documentFile: null as File | null,
|
commitmentHashes: []
|
||||||
certificateJson: null as Record<string, any> | null
|
|
||||||
};
|
|
||||||
|
|
||||||
const wrapper = document.createElement('div');
|
|
||||||
wrapper.style.cssText = 'padding: 2rem; display: flex; flex-direction: column; gap: 2rem; align-items: center;';
|
|
||||||
|
|
||||||
const header = document.createElement('h2');
|
|
||||||
header.textContent = 'Document Validation';
|
|
||||||
header.style.cssText = 'font-size: 1.5rem; font-weight: bold;';
|
|
||||||
wrapper.appendChild(header);
|
|
||||||
|
|
||||||
const boxesContainer = document.createElement('div');
|
|
||||||
boxesContainer.style.cssText = 'display: flex; gap: 2rem;';
|
|
||||||
|
|
||||||
const createDropBox = (label: string, onDrop: (file: File) => void) => {
|
|
||||||
const box = document.createElement('div');
|
|
||||||
box.style.cssText = `
|
|
||||||
width: 250px; height: 150px;
|
|
||||||
border: 2px dashed #888;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
text-align: center;
|
|
||||||
padding: 1rem;
|
|
||||||
cursor: pointer;
|
|
||||||
background: #fafafa;
|
|
||||||
`;
|
|
||||||
box.textContent = `Drop ${label} here`;
|
|
||||||
box.ondragover = e => { e.preventDefault(); box.style.background = '#eee'; };
|
|
||||||
box.ondragleave = () => { box.style.background = '#fafafa'; };
|
|
||||||
box.ondrop = async e => {
|
|
||||||
e.preventDefault();
|
|
||||||
const file = e.dataTransfer?.files?.[0];
|
|
||||||
if (!file) return;
|
|
||||||
if (label === 'Document') {
|
|
||||||
if (file.type === 'application/pdf') {
|
|
||||||
onDrop(file);
|
|
||||||
box.textContent = `${label} uploaded: ${file.name}`;
|
|
||||||
box.style.borderColor = 'green';
|
|
||||||
box.style.background = '#e6ffed';
|
|
||||||
} else {
|
|
||||||
alert('Please drop a valid PDF file.');
|
|
||||||
}
|
|
||||||
} else if (label === 'Certificate') {
|
|
||||||
try {
|
|
||||||
const text = await file.text();
|
|
||||||
const json = JSON.parse(text);
|
|
||||||
onDrop(file);
|
|
||||||
state.certificateJson = json;
|
|
||||||
box.textContent = `Certificate loaded: ${file.name}`;
|
|
||||||
box.style.borderColor = 'green';
|
|
||||||
box.style.background = '#e6ffed';
|
|
||||||
} catch (err) {
|
|
||||||
alert('Invalid certificate file. Must be valid JSON.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return box;
|
|
||||||
};
|
|
||||||
|
|
||||||
const docBox = createDropBox('Document', file => {
|
|
||||||
state.documentFile = file;
|
|
||||||
checkSuccess();
|
|
||||||
});
|
|
||||||
|
|
||||||
const certBox = createDropBox('Certificate', file => {
|
|
||||||
checkSuccess();
|
|
||||||
});
|
|
||||||
|
|
||||||
boxesContainer.appendChild(docBox);
|
|
||||||
boxesContainer.appendChild(certBox);
|
|
||||||
wrapper.appendChild(boxesContainer);
|
|
||||||
|
|
||||||
container.appendChild(wrapper);
|
|
||||||
|
|
||||||
function checkSuccess() {
|
|
||||||
if (state.documentFile && state.certificateJson) {
|
|
||||||
showSuccessScreen();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showSuccessScreen() {
|
|
||||||
container.innerHTML = '';
|
container.innerHTML = '';
|
||||||
|
container.style.display = 'flex';
|
||||||
|
container.style.justifyContent = 'center';
|
||||||
|
container.style.gap = '2rem';
|
||||||
|
container.style.padding = '2rem';
|
||||||
|
|
||||||
const successWrapper = document.createElement('div');
|
const createDropButton = (label: string, onDrop: (file: File, updateVisuals: (file: File) => void) => void): HTMLElement => {
|
||||||
successWrapper.style.cssText = `
|
const button = document.createElement('div');
|
||||||
padding: 4rem;
|
button.style.cssText = `
|
||||||
text-align: center;
|
width: 200px;
|
||||||
|
height: 100px;
|
||||||
|
border: 2px dashed #888;
|
||||||
|
border-radius: 8px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 1.5rem;
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
background: #f8f8f8;
|
||||||
|
text-align: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const checkmark = document.createElement('div');
|
|
||||||
checkmark.textContent = '✅';
|
|
||||||
checkmark.style.cssText = 'font-size: 4rem;';
|
|
||||||
successWrapper.appendChild(checkmark);
|
|
||||||
|
|
||||||
const successMsg = document.createElement('div');
|
|
||||||
successMsg.textContent = 'Document Verified Successfully!';
|
|
||||||
successMsg.style.cssText = 'font-size: 1.25rem; font-weight: bold; color: green;';
|
|
||||||
successWrapper.appendChild(successMsg);
|
|
||||||
|
|
||||||
// === Display file names ===
|
|
||||||
const docLabel = document.createElement('div');
|
|
||||||
docLabel.textContent = `Document: ${state.documentFile!.name}`;
|
|
||||||
successWrapper.appendChild(docLabel);
|
|
||||||
|
|
||||||
const certLabel = document.createElement('div');
|
|
||||||
certLabel.textContent = `Certificate: ${state.certificateJson!.name}`;
|
|
||||||
successWrapper.appendChild(certLabel);
|
|
||||||
|
|
||||||
// === Mocked verification data ===
|
|
||||||
const documentHash = randomHex32();
|
|
||||||
const fieldName = "owner_name"; // mocked field
|
|
||||||
const transactionId = randomHex32();
|
|
||||||
|
|
||||||
const dataBlock = (label: string, value: string) => {
|
|
||||||
const block = document.createElement('div');
|
|
||||||
block.style.cssText = 'text-align: left; width: 100%; max-width: 600px;';
|
|
||||||
|
|
||||||
const title = document.createElement('div');
|
const title = document.createElement('div');
|
||||||
title.textContent = label;
|
title.textContent = label;
|
||||||
title.style.cssText = 'font-weight: bold; margin-top: 1rem;';
|
|
||||||
|
|
||||||
const code = document.createElement('code');
|
const filename = document.createElement('div');
|
||||||
code.textContent = value;
|
filename.style.cssText = `
|
||||||
code.style.cssText = `
|
font-size: 0.85rem;
|
||||||
display: block;
|
margin-top: 0.5rem;
|
||||||
background: #f0f0f0;
|
color: #444;
|
||||||
padding: 0.5rem;
|
word-break: break-word;
|
||||||
border-radius: 0.375rem;
|
text-align: center;
|
||||||
font-family: monospace;
|
|
||||||
word-break: break-all;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
block.appendChild(title);
|
button.appendChild(title);
|
||||||
block.appendChild(code);
|
button.appendChild(filename);
|
||||||
return block;
|
|
||||||
|
const updateVisuals = (file: File) => {
|
||||||
|
button.style.borderColor = 'green';
|
||||||
|
button.style.background = '#e6ffed';
|
||||||
|
filename.textContent = file.name;
|
||||||
};
|
};
|
||||||
|
|
||||||
successWrapper.appendChild(dataBlock('Document Hash', documentHash));
|
button.ondragover = e => {
|
||||||
successWrapper.appendChild(dataBlock('Field Name', fieldName));
|
e.preventDefault();
|
||||||
successWrapper.appendChild(dataBlock('Transaction ID', transactionId));
|
button.style.background = '#e0e0e0';
|
||||||
|
};
|
||||||
|
|
||||||
// === Restart button ===
|
button.ondragleave = () => {
|
||||||
const restartBtn = document.createElement('button');
|
button.style.background = '#f8f8f8';
|
||||||
restartBtn.textContent = 'Verify Another';
|
};
|
||||||
restartBtn.style.cssText = `
|
|
||||||
margin-top: 2rem;
|
|
||||||
padding: 0.5rem 1.5rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
background: #4f46e5;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 0.375rem;
|
|
||||||
cursor: pointer;
|
|
||||||
`;
|
|
||||||
restartBtn.onclick = () => getDocumentValidation(container);
|
|
||||||
successWrapper.appendChild(restartBtn);
|
|
||||||
|
|
||||||
container.appendChild(successWrapper);
|
button.ondrop = async e => {
|
||||||
|
e.preventDefault();
|
||||||
|
button.style.background = '#f8f8f8';
|
||||||
|
|
||||||
|
const file = e.dataTransfer?.files?.[0];
|
||||||
|
if (!file) return;
|
||||||
|
onDrop(file, updateVisuals);
|
||||||
|
};
|
||||||
|
|
||||||
|
return button;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fileDropButton = createDropButton('Drop file', async (file, updateVisuals) => {
|
||||||
|
try {
|
||||||
|
state.file = file;
|
||||||
|
updateVisuals(file);
|
||||||
|
console.log('Loaded file:', state.file);
|
||||||
|
checkReady();
|
||||||
|
} catch (err) {
|
||||||
|
alert('Failed to drop the file.');
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const certDropButton = createDropButton('Drop certificate', async (file, updateVisuals) => {
|
||||||
|
try {
|
||||||
|
const text = await file.text();
|
||||||
|
const json = JSON.parse(text);
|
||||||
|
if (
|
||||||
|
typeof json === 'object' &&
|
||||||
|
json !== null &&
|
||||||
|
typeof json.pcd_commitment === 'object' &&
|
||||||
|
typeof json.state_id === 'string'
|
||||||
|
) {
|
||||||
|
state.certificate = json as ProcessState;
|
||||||
|
|
||||||
|
state.commitmentHashes = Object.values(json.pcd_commitment).map((h: string) =>
|
||||||
|
h.toLowerCase()
|
||||||
|
);
|
||||||
|
|
||||||
|
updateVisuals(file);
|
||||||
|
console.log('Loaded certificate, extracted hashes:', state.commitmentHashes);
|
||||||
|
checkReady();
|
||||||
|
} else {
|
||||||
|
alert('Invalid certificate structure.');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
alert('Failed to parse certificate JSON.');
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
container.appendChild(fileDropButton);
|
||||||
|
container.appendChild(certDropButton);
|
||||||
|
|
||||||
|
async function checkReady() {
|
||||||
|
if (state.file && state.certificate && state.commitmentHashes.length > 0) {
|
||||||
|
// We take the commited_in and all pcd_commitment keys to reconstruct all the possible hash
|
||||||
|
const fileBlob = {
|
||||||
|
type: state.file.type,
|
||||||
|
data: new Uint8Array(await state.file.arrayBuffer())
|
||||||
|
};
|
||||||
|
const service = await Services.getInstance();
|
||||||
|
const commitedIn = state.certificate.commited_in;
|
||||||
|
let found = false;
|
||||||
|
for (const label of Object.keys(state.certificate.pcd_commitment)) {
|
||||||
|
// Compute the hash for this label
|
||||||
|
console.log(`Computing hash with label ${label}`)
|
||||||
|
const fileHex = service.getHashForFile(commitedIn, label, fileBlob);
|
||||||
|
console.log(`Found hash ${fileHex}`);
|
||||||
|
found = state.commitmentHashes.includes(fileHex);
|
||||||
|
if (found) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
alert('✅ Validation successful: file hash found in pcd_commitment.');
|
||||||
|
} else {
|
||||||
|
alert('❌ Validation failed: file hash NOT found in pcd_commitment.');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user