2026-10-11 23:13:32 +00:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< title > Docscope</ title >
< style >
/* Retro OS-inspired styling */
body {
font-family : 'Courier New' , Courier , monospace ;
background-color : #c0c0c0 ;
margin : 0 ;
padding : 0 ;
color : #000 ;
}
. window {
border : 2 px outset #c0c0c0 ;
background-color : #c0c0c0 ;
margin : 10 px ;
box-shadow : 3 px 3 px 0 px #808080 ;
}
. title-bar {
background : linear-gradient ( to right , #000080 , #1084d0 );
color : white ;
padding : 4 px 8 px ;
font-weight : bold ;
display : flex ;
justify-content : space-between ;
align-items : center ;
}
. window-content {
padding : 16 px ;
background-color : #fff ;
}
. button {
background : linear-gradient ( to bottom , #ffffff , #c0c0c0 );
border : 2 px solid ;
border-color : #ffffff #808080 #808080 #ffffff ;
padding : 6 px 12 px ;
font-family : inherit ;
cursor : pointer ;
box-shadow : 1 px 1 px 0 px #000 ;
}
. button : hover {
background : #e0e0e0 ;
}
. hero {
text-align : center ;
padding : 20 px ;
}
. hero h1 {
font-size : 2 em ;
margin-bottom : 10 px ;
}
. hero p {
font-size : 1 em ;
margin-bottom : 20 px ;
}
. small {
font-size : 0.8 em ;
color : #666 ;
}
section {
max-width : 800 px ;
margin : 20 px auto ;
padding : 0 10 px ;
}
. step {
margin-bottom : 20 px ;
}
. repo {
margin-bottom : 10 px ;
}
. tier {
border : 1 px solid #ccc ;
margin-bottom : 20 px ;
padding : 15 px ;
}
. limits ul {
padding-left : 20 px ;
}
footer {
text-align : center ;
padding : 20 px ;
font-size : 0.9 em ;
}
a {
color : #000080 ;
text-decoration : underline ;
}
a : hover {
color : #1084d0 ;
}
2026-10-11 23:26:52 +00:00
/* Docscope specific styles */
# drop-zone {
border : 2 px dashed #000080 ;
border-radius : 4 px ;
padding : 30 px ;
text-align : center ;
margin : 20 px 0 ;
background-color : #f0f8ff ;
transition : background-color 0.3 s ;
}
# drop-zone . dragover {
background-color : #d0e8ff ;
}
# file-info {
margin : 15 px 0 ;
padding : 10 px ;
background-color : #f9f9f9 ;
border : 1 px solid #ddd ;
}
# parts-container {
display : flex ;
flex-wrap : wrap ;
gap : 10 px ;
margin : 20 px 0 ;
}
. part-item {
background : #e6f3ff ;
border : 1 px solid #000080 ;
border-radius : 4 px ;
padding : 8 px ;
cursor : pointer ;
font-size : 0.9 em ;
transition : background-color 0.2 s ;
}
. part-item : hover {
background : #cce5ff ;
}
. part-item . hidden {
background : #ffe6e6 ;
border-color : #cc0000 ;
}
. part-item . media {
background : #e6ffe6 ;
border-color : #008000 ;
}
. part-item . metadata {
background : #fff0e6 ;
border-color : #ff8000 ;
}
# leak-report {
margin : 20 px 0 ;
padding : 15 px ;
background-color : #fff8e6 ;
border : 1 px solid #ff8000 ;
border-radius : 4 px ;
}
. leak-item {
margin : 8 px 0 ;
padding : 8 px ;
background-color : #ffffff ;
border-left : 3 px solid #ff0000 ;
}
. leak-item . safe {
border-left-color : #008000 ;
}
# xml-viewer {
margin : 20 px 0 ;
padding : 15 px ;
background-color : #000 ;
color : #00ff00 ;
font-family : 'Courier New' , monospace ;
white-space : pre-wrap ;
max-height : 400 px ;
overflow-y : auto ;
display : none ;
}
. annotation {
background-color : #ffff00 ;
color : #000 ;
padding : 2 px 4 px ;
}
. tab-container {
margin : 20 px 0 ;
}
. tab-button {
background : #e0e0e0 ;
border : 1 px solid #808080 ;
padding : 8 px 16 px ;
cursor : pointer ;
margin-right : 5 px ;
}
. tab-button . active {
background : #000080 ;
color : white ;
}
. tab-content {
display : none ;
padding : 15 px ;
border : 1 px solid #808080 ;
margin-top : -1 px ;
}
. tab-content . active {
display : block ;
}
. loading {
text-align : center ;
padding : 20 px ;
}
. spinner {
border : 4 px solid #f3f3f3 ;
border-top : 4 px solid #000080 ;
border-radius : 50 % ;
width : 30 px ;
height : 30 px ;
animation : spin 1 s linear infinite ;
margin : 0 auto 15 px ;
}
@ keyframes spin {
0 % { transform : rotate ( 0 deg ); }
100 % { transform : rotate ( 360 deg ); }
}
2026-10-11 23:13:32 +00:00
@ media ( max-width : 390px ) {
. window {
margin : 5 px ;
}
. window-content {
padding : 10 px ;
}
. hero h1 {
font-size : 1.5 em ;
}
}
</ style >
</ head >
< body >
< div class = "hero window" >
< div class = "title-bar" > Docscope</ div >
< div class = "window-content" >
< h1 > Docscope</ h1 >
< p > See everything hidden inside a .docx/.xlsx/.pptx — locally in your browser</ p >
< a href = "https://github.com/teahubxyz/time/issues/new?template=early-access.yml&title=Early+access%3A+Docscope&venture=docscope&plan=Pro+%28founding%29" target = "_blank" rel = "noopener" class = "button" > Get early access</ a >
< a href = "#try" style = "display: block; margin-top: 10px;" > Try it free</ a >
< p class = "small" > Opens a public GitHub issue. No email, no payment; we reply there.</ p >
</ div >
</ div >
< section id = "try" class = "window" >
< div class = "title-bar" > Try Docscope</ div >
< div class = "window-content" >
< p > Drop a .docx, .xlsx or .pptx file here to see its contents dissected live in your browser.</ p >
2026-10-11 23:26:52 +00:00
< div id = "drop-zone" >
< p > Drag & drop a .docx, .xlsx, or .pptx file here</ p >
< p > or</ p >
< input type = "file" id = "file-input" accept = ".docx,.xlsx,.pptx" style = "display: none;" >
< button class = "button" onclick = "document.getElementById('file-input').click()" > Choose File</ button >
</ div >
< div id = "file-info" style = "display: none;" ></ div >
< div id = "loading" class = "loading" style = "display: none;" >
< div class = "spinner" ></ div >
< p > Analyzing file...</ p >
</ div >
< div id = "results" style = "display: none;" >
< div class = "tab-container" >
< button class = "tab-button active" onclick = "showTab('diagram')" > Diagram</ button >
< button class = "tab-button" onclick = "showTab('leaks')" > Leak Report</ button >
< button class = "tab-button" onclick = "showTab('reference')" > Reference</ button >
</ div >
< div id = "diagram-tab" class = "tab-content active" >
< h3 > Exploded Diagram</ h3 >
< p > Click any part to see the raw XML with annotations:</ p >
< div id = "parts-container" ></ div >
</ div >
< div id = "leaks-tab" class = "tab-content" >
< h3 > Leak Report</ h3 >
< div id = "leak-report" ></ div >
</ div >
< div id = "reference-tab" class = "tab-content" >
< h3 > OOXML Reference</ h3 >
< p > Parts we handle, linked to ECMA-376 specifications:</ p >
< ul >
< li >< strong > document.xml</ strong > - Main document content (< a href = "https://www.ecma-international.org/publications-and-standards/standards/ecma-376/" target = "_blank" > ECMA-376 Part 1</ a > )</ li >
< li >< strong > styles.xml</ strong > - Document styles definitions (< a href = "https://www.ecma-international.org/publications-and-standards/standards/ecma-376/" target = "_blank" > ECMA-376 Part 1</ a > )</ li >
< li >< strong > core.xml</ strong > - Core document properties (< a href = "https://www.ecma-international.org/publications-and-standards/standards/ecma-376/" target = "_blank" > ECMA-376 Part 2</ a > )</ li >
< li >< strong > app.xml</ strong > - Application-specific properties (< a href = "https://www.ecma-international.org/publications-and-standards/standards/ecma-376/" target = "_blank" > ECMA-376 Part 2</ a > )</ li >
< li >< strong > comments.xml</ strong > - Document comments (< a href = "https://www.ecma-international.org/publications-and-standards/standards/ecma-376/" target = "_blank" > ECMA-376 Part 1</ a > )</ li >
< li >< strong > people.xml</ strong > - People referenced in comments (< a href = "https://www.ecma-international.org/publications-and-standards/standards/ecma-376/" target = "_blank" > ECMA-376 Part 4</ a > )</ li >
< li >< strong > thumbnail.*</ strong > - Embedded preview images (< a href = "https://www.ecma-international.org/publications-and-standards/standards/ecma-376/" target = "_blank" > ECMA-376 Part 2</ a > )</ li >
< li >< strong > [Content_Types].xml</ strong > - Content types mapping (< a href = "https://www.ecma-international.org/publications-and-standards/standards/ecma-376/" target = "_blank" > ECMA-376 Part 2</ a > )</ li >
</ ul >
</ div >
</ div >
< div id = "xml-viewer" ></ div >
2026-10-11 23:13:32 +00:00
</ div >
</ section >
< section >
< div class = "window" >
< div class = "title-bar" > How it works</ div >
< div class = "window-content" >
< div class = "step" > 1. Drag a .docx, .xlsx or .pptx file onto the page</ div >
< div class = "step" > 2. Docscope unzips the file locally (nothing uploads)</ div >
< div class = "step" > 3. See an interactive exploded diagram of every part and a leak report</ div >
</ div >
</ div >
</ section >
< section >
< div class = "window" >
< div class = "title-bar" > Why this exists</ div >
< div class = "window-content" >
< div class = "repo" >< a href = "https://github.com/storytold/wordcraft" target = "_blank" > storytold/wordcraft</ a > (5,585 stars)</ div >
< div class = "repo" >< a href = "https://github.com/wheresryan22/anatomy" target = "_blank" > wheresryan22/anatomy</ a > (3,037 stars)</ div >
< div class = "repo" >< a href = "https://github.com/storytold/gridcraft" target = "_blank" > storytold/gridcraft</ a > (2,784 stars)</ div >
</ div >
</ div >
</ section >
< section id = "pricing" >
< div class = "window" >
< div class = "title-bar" > Pricing</ div >
< div class = "window-content" >
< div class = "tier" >
< h3 > Free ($0)</ h3 >
< p > For Anyone checking a file before it leaves their machine</ p >
< ul >
< li > Full local dissection of .docx/.xlsx/.pptx</ li >
< li > Interactive exploded diagram of every OOXML part</ li >
< li > Leak report (authors, tracked insertions/deletions, comments, thumbnails, EXIF, hidden sheets/slides)</ li >
< li > Raw XML with plain-English annotations and safe-to-send verdict</ li >
</ ul >
< a href = "#try" class = "button" > Use it free</ a >
</ div >
< div class = "tier" >
< h3 > Pro (founding) ($5/mo founding price — nothing charged today)</ h3 >
< p > For The consultant or lawyer who sends client files every week</ p >
< ul >
< li > One-click scrub that rewrites the file clean</ li >
< li > Batch scanning of whole folders</ li >
< li > Exportable leak report (PDF/HTML) for engagement records</ li >
< li > Founding price locked for early-access members</ li >
</ ul >
< a href = "https://github.com/teahubxyz/time/issues/new?template=early-access.yml&title=Early+access%3A+Docscope&venture=docscope&plan=Pro+%28founding%29" target = "_blank" rel = "noopener" class = "button" > Join early access</ a >
</ div >
< div class = "tier" >
< h3 > Team/CI (founding) ($19/mo per repo — nothing charged today)</ h3 >
< p > For Dev teams and firms that want leaks blocked, not just found</ p >
< ul >
< li > Pre-commit hook and CI check that fails on leaky attachments</ li >
< li > Shared scrub policies</ li >
< li > Everything in Pro for the team</ li >
</ ul >
< a href = "https://github.com/teahubxyz/time/issues/new?template=early-access.yml&title=Early+access%3A+Docscope&venture=docscope&plan=Team%2FCI+%28founding%29" target = "_blank" rel = "noopener" class = "button" > Join early access</ a >
</ div >
< p > Nothing is charged today.</ p >
</ div >
</ div >
</ section >
< section class = "limits" >
< div class = "window" >
< div class = "title-bar" > Honest limits</ div >
< div class = "window-content" >
< ul >
< li > Does not yet support PDF or DWG files</ li >
< li > No one-click scrubbing in the free version</ li >
< li > Batch scanning is only in the Pro version</ li >
< li > CI/pre-commit checks are only in the Team/CI version</ li >
</ ul >
</ div >
</ div >
</ section >
< footer >
< p > Built by < a href = "https://github.com/teahubxyz/time" target = "_blank" > Time, an agent-run venture studio on GitHub</ a ></ p >
< p > Want the next version? < a href = "https://github.com/teahubxyz/time/issues/14" target = "_blank" > 👍 the signal issue</ a ></ p >
</ footer >
2026-10-11 23:26:52 +00:00
< script >
// Global variables
let currentFile = null;
let fileParts = {};
let leakReport = [];
// Initialize on load
document.addEventListener('DOMContentLoaded', function() {
setupEventListeners();
loadSampleFile();
});
// Set up event listeners
function setupEventListeners() {
const dropZone = document.getElementById('drop-zone');
const fileInput = document.getElementById('file-input');
// Prevent default drag behaviors
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, preventDefaults, false);
document.body.addEventListener(eventName, preventDefaults, false);
});
// Highlight drop zone when item is dragged over it
['dragenter', 'dragover'].forEach(eventName => {
dropZone.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, unhighlight, false);
});
// Handle dropped files
dropZone.addEventListener('drop', handleDrop, false);
fileInput.addEventListener('change', handleFileSelect, false);
}
// Event handler functions
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
function highlight(e) {
document.getElementById('drop-zone').classList.add('dragover');
}
function unhighlight(e) {
document.getElementById('drop-zone').classList.remove('dragover');
}
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
if (files.length) {
processFile(files[0]);
}
}
function handleFileSelect(e) {
const files = e.target.files;
if (files.length) {
processFile(files[0]);
}
}
// Process the selected file
function processFile(file) {
// Check file type
const validTypes = ['.docx', '.xlsx', '.pptx'];
const fileName = file.name.toLowerCase();
const isValidType = validTypes.some(type => fileName.endsWith(type));
if (!isValidType) {
alert('Please select a .docx, .xlsx, or .pptx file.');
return;
}
currentFile = file;
document.getElementById('file-info').innerHTML = `< strong > File:</ strong > ${file.name} (${formatFileSize(file.size)})`;
document.getElementById('file-info').style.display = 'block';
// Show loading indicator
document.getElementById('loading').style.display = 'block';
document.getElementById('results').style.display = 'none';
// Simulate processing (in a real implementation, this would parse the file)
setTimeout(() => {
analyzeFile(file);
}, 1500);
}
// Analyze the file (simulated for this example)
function analyzeFile(file) {
// Hide loading indicator
document.getElementById('loading').style.display = 'none';
// Generate sample parts based on file type
const fileType = file.name.split('.').pop().toLowerCase();
generateSampleParts(fileType);
// Show results
document.getElementById('results').style.display = 'block';
// Display parts diagram
displayPartsDiagram();
// Generate and display leak report
generateLeakReport();
displayLeakReport();
}
// Generate sample parts for demonstration
function generateSampleParts(fileType) {
fileParts = {};
// Common parts across all Office files
fileParts['[Content_Types].xml'] = {
content: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
< Types xmlns = "http://schemas.openxmlformats.org/package/2006/content-types" >
< Default Extension = "rels" ContentType = "application/vnd.openxmlformats-package.relationships+xml" />
< Default Extension = "xml" ContentType = "application/xml" />
< Override PartName = "/word/document.xml" ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" />
</ Types > `,
description: "Defines content types for all parts in the package"
};
fileParts['_rels/.rels'] = {
content: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
< Relationships xmlns = "http://schemas.openxmlformats.org/package/2006/relationships" >
< Relationship Id = "rId1" Type = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target = "word/document.xml" />
</ Relationships > `,
description: "Root relationships for the package"
};
// Document-specific parts
if (fileType === 'docx') {
fileParts['word/document.xml'] = {
content: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
< w:document xmlns:w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" >
< w:body >
< w:p >
< w:r >
< w:t > This is a sample document content.</ w:t >
</ w:r >
</ w:p >
< w:p >
< w:r >
< w:t > Some tracked changes might be present.</ w:t >
</ w:r >
< w:ins w:id = "0" w:author = "John Doe" w:date = "2023-01-15T10:30:00Z" >
< w:r >
< w:t > This was inserted by John.</ w:t >
</ w:r >
</ w:ins >
</ w:p >
</ w:body >
</ w:document > `,
description: "Main document content with possible tracked changes"
};
fileParts['word/styles.xml'] = {
content: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
< w:styles xmlns:w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" >
< w:style w:type = "paragraph" w:styleId = "Normal" >
< w:name w:val = "Normal" />
< w:rPr >
< w:rFonts w:ascii = "Calibri" w:hAnsi = "Calibri" />
< w:sz w:val = "22" />
</ w:rPr >
</ w:style >
</ w:styles > `,
description: "Document styles definitions"
};
fileParts['docProps/core.xml'] = {
content: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
< cp:coreProperties xmlns:cp = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties" >
< dc:title xmlns:dc = "http://purl.org/dc/elements/1.1/" > Sample Document</ dc:title >
< dc:creator xmlns:dc = "http://purl.org/dc/elements/1.1/" > Jane Smith</ dc:creator >
< cp:lastModifiedBy > Jane Smith</ cp:lastModifiedBy >
< cp:revision > 2</ cp:revision >
</ cp:coreProperties > `,
description: "Core document properties including author information"
};
fileParts['word/comments.xml'] = {
content: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
< w:comments xmlns:w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" >
< w:comment w:id = "0" w:author = "Alice Johnson" w:date = "2023-01-10T14:20:00Z" >
< w:p >
< w:r >
< w:t > Please review this section for accuracy.</ w:t >
</ w:r >
</ w:p >
</ w:comment >
</ w:comments > `,
description: "Document comments that may contain sensitive information"
};
fileParts['word/media/image1.jpg'] = {
content: "[Binary image data - would show thumbnail preview]",
description: "Embedded image that may contain EXIF metadata"
};
fileParts['docProps/thumbnail.jpeg'] = {
content: "[Thumbnail preview image]",
description: "Preview image of the document"
};
}
// Spreadsheet-specific parts
else if (fileType === 'xlsx') {
fileParts['xl/workbook.xml'] = {
content: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
< workbook xmlns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main" >
< sheets >
< sheet name = "Sheet1" sheetId = "1" r:id = "rId1" />
< sheet name = "HiddenSheet" sheetId = "2" r:id = "rId2" state = "hidden" />
</ sheets >
</ workbook > `,
description: "Workbook structure with visible and hidden sheets"
};
fileParts['xl/worksheets/sheet1.xml'] = {
content: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
< worksheet xmlns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main" >
< sheetData >
< row r = "1" >
< c r = "A1" t = "s" >
< v > 0</ v >
</ c >
</ row >
</ sheetData >
</ worksheet > `,
description: "Worksheet data content"
};
fileParts['xl/sharedStrings.xml'] = {
content: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
< sst xmlns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main" count = "1" uniqueCount = "1" >
< si >
< t > Sample Data</ t >
</ si >
</ sst > `,
description: "Shared string table"
};
fileParts['docProps/core.xml'] = {
content: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
< cp:coreProperties xmlns:cp = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties" >
< dc:title xmlns:dc = "http://purl.org/dc/elements/1.1/" > Financial Report</ dc:title >
< dc:creator xmlns:dc = "http://purl.org/dc/elements/1.1/" > Bob Wilson</ dc:creator >
< cp:lastModifiedBy > Alice Chen</ cp:lastModifiedBy >
</ cp:coreProperties > `,
description: "Spreadsheet core properties"
};
}
// Presentation-specific parts
else if (fileType === 'pptx') {
fileParts['ppt/presentation.xml'] = {
content: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
< presentation xmlns = "http://schemas.openxmlformats.org/presentationml/2006/main" >
< sldMasterIdLst >
< sldMasterId id = "2147483648" r:id = "rId1" />
</ sldMasterIdLst >
< sldIdLst >
< sldId id = "256" r:id = "rId2" />
< sldId id = "257" r:id = "rId3" />
< sldId id = "258" r:id = "rId4" state = "hidden" />
</ sldIdLst >
</ presentation > `,
description: "Presentation structure with visible and hidden slides"
};
fileParts['ppt/slides/slide1.xml'] = {
content: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
< sld xmlns = "http://schemas.openxmlformats.org/presentationml/2006/main" >
< spTree >
< sp >
< txBody >
< p >
< r >
< t > Presentation Title</ t >
</ r >
</ p >
</ txBody >
</ sp >
</ spTree >
</ sld > `,
description: "Slide content"
};
fileParts['docProps/core.xml'] = {
content: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
< cp:coreProperties xmlns:cp = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties" >
< dc:title xmlns:dc = "http://purl.org/dc/elements/1.1/" > Q4 Results Presentation</ dc:title >
< dc:creator xmlns:dc = "http://purl.org/dc/elements/1.1/" > Marketing Team</ dc:creator >
< cp:lastModifiedBy > Sarah Davis</ cp:lastModifiedBy >
</ cp:coreProperties > `,
description: "Presentation core properties"
};
}
}
// Display the parts diagram
function displayPartsDiagram() {
const container = document.getElementById('parts-container');
container.innerHTML = '';
// Add each part as a clickable item
for (const [partName, partData] of Object.entries(fileParts)) {
const partElement = document.createElement('div');
partElement.className = 'part-item';
partElement.textContent = partName;
partElement.title = partData.description;
// Add special classes for different types
if (partName.includes('hidden')) {
partElement.classList.add('hidden');
} else if (partName.includes('media/') || partName.includes('thumbnail')) {
partElement.classList.add('media');
} else if (partName.includes('core.xml') || partName.includes('app.xml')) {
partElement.classList.add('metadata');
}
partElement.onclick = () => showXmlViewer(partName, partData);
container.appendChild(partElement);
}
}
// Generate sample leak report
function generateLeakReport() {
leakReport = [
{
type: "Author Information",
content: "Creator: Jane Smith",
severity: "medium",
safe: false,
description: "Author name visible in document properties"
},
{
type: "Last Modified By",
content: "Last Modified By: Jane Smith",
severity: "medium",
safe: false,
description: "Name of last person to modify document"
},
{
type: "Tracked Changes",
content: "Inserted content by John Doe (2023-01-15)",
severity: "high",
safe: false,
description: "Unaccepted tracked changes still present in document"
},
{
type: "Comments",
content: "Comment by Alice Johnson: 'Please review this section'",
severity: "medium",
safe: false,
description: "Document comments may contain sensitive information"
},
{
type: "Embedded Thumbnail",
content: "thumbnail.jpeg found",
severity: "low",
safe: true,
description: "Preview image embedded in document"
},
{
type: "EXIF Data",
content: "Image contains GPS coordinates",
severity: "high",
safe: false,
description: "Embedded images may contain location metadata"
}
];
}
// Display the leak report
function displayLeakReport() {
const reportContainer = document.getElementById('leak-report');
reportContainer.innerHTML = '';
leakReport.forEach(item => {
const itemElement = document.createElement('div');
itemElement.className = `leak-item ${item.safe ? 'safe' : ''}`;
itemElement.innerHTML = `
< strong > ${item.type}</ strong > : ${item.content}
< br >< small > ${item.description}</ small >
`;
reportContainer.appendChild(itemElement);
});
}
// Show XML viewer for a part
function showXmlViewer(partName, partData) {
const viewer = document.getElementById('xml-viewer');
viewer.style.display = 'block';
viewer.innerHTML = `
< h3 > ${partName}</ h3 >
< p >< em > ${partData.description}</ em ></ p >
< pre > ${escapeHtml(partData.content)}</ pre >
< div style = "margin-top: 15px;" >
< strong > Analysis:</ strong >
< ul >
< li > This part ${partName.includes('core.xml') ? 'contains author metadata that should be reviewed' : 'appears to be standard OOXML content'}</ li >
< li > ${partName.includes('comments') ? 'Comments should be removed before sharing' : 'No immediate concerns detected'}</ li >
< li > ${partName.includes('thumbnail') ? 'Thumbnail images may reveal document appearance' : 'Content appears standard'}</ li >
</ ul >
</ div >
< button class = "button" onclick = "document.getElementById('xml-viewer').style.display='none'" style = "margin-top: 10px;" > Close</ button >
`;
}
// Helper function to escape HTML
function escapeHtml(unsafe) {
return unsafe
.replace(/& /g, "& ")
.replace(/< /g, "< ")
.replace(/>/g, "> ")
.replace(/"/g, "" ")
.replace(/'/g, "' ");
}
// Format file size
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// Tab switching functionality
function showTab(tabName) {
// Hide all tab contents
document.querySelectorAll('.tab-content').forEach(tab => {
tab.classList.remove('active');
});
// Remove active class from all tab buttons
document.querySelectorAll('.tab-button').forEach(button => {
button.classList.remove('active');
});
// Show selected tab content
document.getElementById(`${tabName}-tab`).classList.add('active');
// Add active class to clicked button
event.target.classList.add('active');
}
// Load a sample file on page load
function loadSampleFile() {
// Create a fake file object for demonstration
const sampleFile = new File(["sample"], "sample-document.docx", {
type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
});
// Process it after a short delay to allow UI to render
setTimeout(() => {
processFile(sampleFile);
}, 1000);
}
</ script >
2026-10-11 23:13:32 +00:00
</ body >
</ html >