Move data inside package and update references

This commit is contained in:
thePR0M3TH3AN
2025-06-21 12:20:51 -04:00
parent c5b6077eee
commit b72d726bd5
31 changed files with 8 additions and 6 deletions

View File

@@ -17,11 +17,13 @@ ROOT = Path(__file__).resolve().parent.parent
def _template_res(*parts) -> Traversable:
return resources.files(__package__).joinpath('..', 'templates', *parts)
"""Return a Traversable for files under the packaged ``templates`` folder."""
return resources.files(__package__).joinpath('templates', *parts)
def _src_res(*parts) -> Traversable:
return resources.files(__package__).joinpath('..', 'src', *parts)
"""Return a Traversable for files under the packaged ``src`` folder."""
return resources.files(__package__).joinpath('src', *parts)
def require_cmd(cmd: str):

144
voxvera/src/README.md Normal file
View File

@@ -0,0 +1,144 @@
# HTML/CSS/JS Obfuscation Script
This repository contains two Bash scripts that obfuscate and minify the flyer's HTML files. `obfuscate_index.sh` processes `index-master.html` into `index.html`, and `obfuscate_nostr.sh` does the same for `nostr-master.html` to produce `nostr.html`.
## Prerequisites
- **Debian/Ubuntu**: This script is designed to work on Debian-based systems.
- **Node.js**: Terser and html-minifier-terser require Node.js to be installed.
- **qrencode**: Generates the QR codes used in the flyers.
### Install Node.js and npm on Debian
1. **Update your package list:**
```bash
sudo apt update
```
2. **Install Node.js and npm:**
```bash
sudo apt install nodejs npm -y
```
3. **Verify the installation:**
```bash
node -v
npm -v
```
### Install Additional Packages
The helper scripts rely on a few system utilities:
```bash
sudo apt install -y jq qrencode imagemagick poppler-utils
```
### Install Required Tools
Install the Node-based tools used by the obfuscation scripts:
```bash
npm install -g javascript-obfuscator html-minifier-terser
```
You can also run `../setup.sh` from the repository root to install all
prerequisites automatically.
## Script Usage
### Running the Scripts
1. **Ensure both `obfuscate_index.sh` and `obfuscate_nostr.sh` are available.**
2. **Make the script executable:**
```bash
chmod +x obfuscate_index.sh obfuscate_nostr.sh
```
3. **Run the desired script:**
```bash
./obfuscate_index.sh or ./obfuscate_nostr.sh
```
### Script Details
- **Input Files:** `obfuscate_index.sh` expects `index-master.html` and `obfuscate_nostr.sh` uses `nostr-master.html`.
- **Output Files:** `obfuscate_index.sh` writes `index.html` and `obfuscate_nostr.sh` writes `nostr.html`.
- **Error Handling:** Each script verifies that its input file exists before proceeding. Missing files result in an error.
- **Terser and HTML-Minifier-Terser:** The script first uses Terser to obfuscate any embedded JavaScript, then minifies the entire HTML file, including embedded CSS and JavaScript.
### Script Example
```bash
#!/bin/bash
# Input and output file names
input_file="index-master.html"
output_file="index.html"
# Check if the input file exists
if [ ! -f "$input_file" ]; then
echo "Input file $input_file does not exist."
exit 1
fi
# Obfuscate embedded JavaScript using terser
terser_output=$(mktemp)
terser --compress --mangle -- "$input_file" > "$terser_output"
# Minify HTML, including the embedded CSS and the obfuscated JavaScript
html-minifier-terser \
--collapse-whitespace \
--minify-css true \
--minify-js true \
--remove-comments \
--remove-empty-attributes \
--output "$output_file" \
"$terser_output"
# Clean up temporary file
rm "$terser_output"
echo "Obfuscation and minification complete. Output saved as $output_file."
```
A similar script `obfuscate_nostr.sh` follows the same pattern but operates on `nostr-master.html` and outputs `nostr.html`.
## Editing the Script in Visual Studio Code (VSCode)
If you prefer to use Visual Studio Code to edit and run these scripts:
1. **Install VSCode:**
- Follow the official [Visual Studio Code installation guide](https://code.visualstudio.com/docs/setup/linux) for Debian-based systems.
2. **Open your project in VSCode:**
```bash
code /path/to/your/project
```
3. **Edit** `obfuscate_index.sh` or `obfuscate_nostr.sh` in the file explorer.
4. **Run the desired script** within the VSCode terminal:
- Open the terminal in VSCode: `View > Terminal`.
- Run the script:
```bash
./obfuscate_index.sh or ./obfuscate_nostr.sh
```
## Creating and Hosting a Flyer
The `voxvera` CLI automates filling `config.json`, building the HTML files, and copying everything into a new directory under `host/`.
### Usage
```bash
# interactive mode
voxvera init && voxvera build
# use an alternate config file
voxvera init --config path/to/custom.json && voxvera build --config path/to/custom.json
# use an existing filled PDF form
voxvera init --from-pdf path/to/form.pdf && voxvera build
```
By default the script updates `src/config.json`. Use the `-c` option to specify a different file. After answering the prompts (or extracting from the PDF), `index.html` and `nostr.html` are generated and copied along with the QR code images and PDFs. The files end up in `host/<subdomain>` which can be served statically.
QR codes are built automatically during this process. After the configuration is updated, the CLI regenerates the QR codes by invoking `generate_qr.sh` to read the URLs from `config.json` and produce `qrcode-content.png` and `qrcode-tear-offs.png`.

12
voxvera/src/config.json Normal file
View File

@@ -0,0 +1,12 @@
{
"name": "Vox Vera Printable Flyers",
"subdomain": "voxvera",
"title": "TOP SECRET",
"subtitle": "DO <span class=\\\"redacted\\\">NOT</span> DISTRIBUTE",
"headline": "OPERATION VOX VERA",
"content": "Break free from censorship with VoxVera. An anonymous guerrilla marketing and message-spreading tool. Whether online or in the physical world, it can empower you to spread your ideas boldly, shielded by complete anonymity (if you host over Tor). Download the code, design a flyer site, host it online and amplify your message.\\n\\nUse memetic power to share your ideas in your school, workplace, online communities, or even globally. VoxVera ensures your message resonates far and wide, with tear-off sections featuring unique URLs and QR codes for easy reprinting.\\n\\nPrivacy can be maintained. Flyers can be shared via the Tor network, protecting hoster and users from censorship.\\n\\nJoin us in a revolution that values truth and transparency. Together, we can build a network of informed citizens who are unafraid to speak out.\n",
"url_message": "Follow this link to learn more. Use Tor Browser.",
"url": "https://voxvera.org/",
"tear_off_link": "https://voxvera.org/",
"binary_message": "0110010 0101011 0110010 0111101 0110100"
}

View File

@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Legacy wrapper for voxvera Python CLI
set -e
if command -v voxvera >/dev/null 2>&1; then
voxvera "$@"
else
python3 -m voxvera "$@"
fi

BIN
voxvera/src/example.pdf Normal file

Binary file not shown.

View File

@@ -0,0 +1,29 @@
#!/bin/bash
set -e
CONFIG="${1:-config.json}"
# Ensure dependencies
command -v jq >/dev/null 2>&1 || { echo "jq is required" >&2; exit 1; }
command -v qrencode >/dev/null 2>&1 || { echo "qrencode is required" >&2; exit 1; }
command -v convert >/dev/null 2>&1 || { echo "ImageMagick convert is required" >&2; exit 1; }
url=$(jq -r '.url' "$CONFIG")
tear=$(jq -r '.tear_off_link' "$CONFIG")
[ -n "$url" ] || { echo "URL missing in $CONFIG" >&2; exit 1; }
[ -n "$tear" ] || { echo "tear_off_link missing in $CONFIG" >&2; exit 1; }
tmp_content=$(mktemp)
tmp_tear=$(mktemp)
qrencode -o "$tmp_content" -s 10 -m 0 "$url"
qrencode -o "$tmp_tear" -s 10 -m 0 "$tear"
convert "$tmp_content" -resize 128x128 "qrcode-content.png"
convert "$tmp_tear" -resize 128x128 "qrcode-tear-offs.png"
rm -f "$tmp_content" "$tmp_tear"
echo "QR codes generated"

View File

@@ -0,0 +1,21 @@
#!/bin/bash
set -euo pipefail
IMPORT_DIR="imports"
shopt -s nullglob
files=("$IMPORT_DIR"/*.json)
if [[ ${#files[@]} -eq 0 ]]; then
echo "No JSON files found in $IMPORT_DIR"
exit 0
fi
for json in "${files[@]}"; do
echo "Processing $json"
cp "$json" src/config.json
subdomain=$(jq -r '.subdomain' "$json")
dest="host/$subdomain"
rm -rf "$dest"
voxvera build --config src/config.json
done

View File

@@ -0,0 +1,501 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1024, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title id="site-title">Vox Vera Printable Flyers</title> <!-- Title will be replaced -->
<style>
body {
font-family: 'Courier New', Courier, monospace;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 100vh;
box-sizing: border-box;
overflow: hidden;
background-color: #ffffff;
}
a {
color: #b80000;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.wrapper {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 100%;
width: 100%;
}
.container {
display: flex;
flex-direction: row;
height: 11in;
width: 8.5in;
border: 1px solid #000;
box-sizing: border-box;
overflow: hidden;
page-break-inside: avoid;
}
.print-button-container {
margin-top: 20px;
}
.print-button {
padding: 10px 20px;
font-size: 14px;
cursor: pointer;
background-color: #000;
color: #fff;
border: none;
border-radius: 0px;
}
.print-button:hover {
background-color: #444;
}
.download-button {
padding: 10px 20px;
font-size: 14px;
cursor: pointer;
background-color: #000;
color: #fff;
border: none;
border-radius: 0px;
}
.download-button:hover {
background-color: #444;
}
.left-tear-offs {
width: 3.75in;
padding: 8px;
border-right: 1px dashed #000;
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 5px;
box-sizing: border-box;
}
.tear-off {
display: flex;
padding: 5px;
border: 1px dashed #000;
font-size: 10px;
box-sizing: border-box;
page-break-inside: avoid;
align-items: flex-start;
}
.tear-off-text {
flex: 1;
min-width: 0;
word-wrap: break-word;
overflow-wrap: break-word;
word-break: break-all;
}
.tear-off a {
color: #b80000;
text-decoration: none;
}
.tear-off a:hover {
text-decoration: underline;
}
.qr-code {
width: 80px;
height: 80px;
border: 0px solid #000;
margin-left: 10px;
flex-shrink: 0;
}
.qr-code img {
width: 100%;
height: 100%;
object-fit: contain;
}
.content {
width: calc(8.5in - 3.75in);
padding: 20px;
text-align: center;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-between;
page-break-inside: avoid;
overflow-wrap: break-word;
}
h1 {
margin: 0;
margin-bottom: 10px;
font-size: 24px;
letter-spacing: 2px;
}
.distribute {
font-size: 18px;
letter-spacing: 6px;
}
.redacted {
text-decoration: line-through;
}
.message {
flex: 1;
margin-top: 10px;
font-size: 14px;
line-height: 1.4;
text-align: left;
overflow-wrap: break-word;
display: flex;
flex-direction: column;
justify-content: flex-end;
white-space: pre-wrap;
box-sizing: border-box;
position: relative;
}
.text-container {
flex: 1;
width: 100%;
height: 100%;
border: none;
outline: none;
font-family: 'Courier New', Courier, monospace;
font-size: 14px;
line-height: 1.4;
white-space: pre-wrap;
overflow: hidden;
box-sizing: border-box;
}
.qr-code-body {
width: 100%;
height: auto;
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
padding: 0;
box-sizing: border-box;
}
.qr-code-body img {
width: 80px;
height: 80px;
object-fit: contain;
flex-shrink: 0;
}
.qr-code-url {
font-size: 12px;
text-align: left;
word-wrap: break-word;
overflow-wrap: break-word;
hyphens: auto;
flex-grow: 1;
margin-right: 10px;
max-width: 60%;
}
hr {
border: none;
border-top: 1px solid #000;
width: 100%;
margin: 10px 0;
}
.footer {
font-size: 10px;
overflow-wrap: break-word;
text-align: center;
align-self: center;
width: 100%;
padding: 10px 0;
box-sizing: border-box;
border-top: 1px solid #000;
}
.footer p {
margin: 0;
padding: 0;
}
.footer .binary {
margin-bottom: 5px;
margin-top: 20px;
}
.footer .credit {
font-size: 12px;
margin-top: 5px;
}
@media print {
body, html {
width: 8.5in;
height: 11in;
margin: 0;
padding: 0;
}
.container {
box-shadow: none;
border: none;
page-break-inside: avoid;
margin: 0;
padding: 0;
width: 8.5in;
height: 11in;
}
.print-button {
display: none;
}
.download-button {
display: none;
}
body {
transform: none;
}
}
.print-button {
margin-top: 20px;
padding: 10px 20px;
font-size: 14px;
cursor: pointer;
background-color: #000;
color: #fff;
border: none;
border-radius: 0px;
}
.print-button:hover {
background-color: #444;
}
</style>
</head>
<body>
<div class="container">
<div class="left-tear-offs">
<div class="tear-off">
<div class="tear-off-text">
Use Tor Browser<br><br>
to help spread this message go to<br>
<a class="tear-off-link" href="#">Loading...</a><br> <!-- The class is used instead of an id -->
click the button below to print
</div>
<div class="qr-code">
<img src="qrcode-tear-offs.png" alt="QR Code">
</div>
</div>
<div class="tear-off">
<div class="tear-off-text">
Use Tor Browser<br><br>
to help spread this message go to<br>
<a class="tear-off-link" href="#">Loading...</a><br> <!-- The class is used instead of an id -->
click the button below to print
</div>
<div class="qr-code">
<img src="qrcode-tear-offs.png" alt="QR Code">
</div>
</div>
<div class="tear-off">
<div class="tear-off-text">
Use Tor Browser<br><br>
to help spread this message go to<br>
<a class="tear-off-link" href="#">Loading...</a><br> <!-- The class is used instead of an id -->
click the button below to print
</div>
<div class="qr-code">
<img src="qrcode-tear-offs.png" alt="QR Code">
</div>
</div>
<div class="tear-off">
<div class="tear-off-text">
Use Tor Browser<br><br>
to help spread this message go to<br>
<a class="tear-off-link" href="#">Loading...</a><br> <!-- The class is used instead of an id -->
click the button below to print
</div>
<div class="qr-code">
<img src="qrcode-tear-offs.png" alt="QR Code">
</div>
</div>
<div class="tear-off">
<div class="tear-off-text">
Use Tor Browser<br><br>
to help spread this message go to<br>
<a class="tear-off-link" href="#">Loading...</a><br> <!-- The class is used instead of an id -->
click the button below to print
</div>
<div class="qr-code">
<img src="qrcode-tear-offs.png" alt="QR Code">
</div>
</div>
<div class="tear-off">
<div class="tear-off-text">
Use Tor Browser<br><br>
to help spread this message go to<br>
<a class="tear-off-link" href="#">Loading...</a><br> <!-- The class is used instead of an id -->
click the button below to print
</div>
<div class="qr-code">
<img src="qrcode-tear-offs.png" alt="QR Code">
</div>
</div>
<div class="tear-off">
<div class="tear-off-text">
Use Tor Browser<br><br>
to help spread this message go to<br>
<a class="tear-off-link" href="#">Loading...</a><br> <!-- The class is used instead of an id -->
click the button below to print
</div>
<div class="qr-code">
<img src="qrcode-tear-offs.png" alt="QR Code">
</div>
</div>
<div class="tear-off">
<div class="tear-off-text">
Use Tor Browser<br><br>
to help spread this message go to<br>
<a class="tear-off-link" href="#">Loading...</a><br> <!-- The class is used instead of an id -->
click the button below to print
</div>
<div class="qr-code">
<img src="qrcode-tear-offs.png" alt="QR Code">
</div>
</div>
<div class="tear-off">
<div class="tear-off-text">
Use Tor Browser<br><br>
to help spread this message go to<br>
<a class="tear-off-link" href="#">Loading...</a><br> <!-- The class is used instead of an id -->
click the button below to print
</div>
<div class="qr-code">
<img src="qrcode-tear-offs.png" alt="QR Code">
</div>
</div>
<div class="tear-off">
<div class="tear-off-text">
Use Tor Browser<br><br>
to help spread this message go to<br>
<a class="tear-off-link" href="#">Loading...</a><br> <!-- The class is used instead of an id -->
click the button below to print
</div>
<div class="qr-code">
<img src="qrcode-tear-offs.png" alt="QR Code">
</div>
</div>
<!-- Repeat similar structure for other tear-offs -->
</div>
<div class="content">
<h1 id="top-secret-title">Loading...</h1> <!-- "Top Secret" title will be replaced -->
<div class="distribute" id="do-not-distribute">Loading...</div> <!-- "DO NOT DISTRIBUTE" message will be replaced -->
<h1 id="operation-title-2"><br>Loading...</h1> <!-- "Operation Vox Vera" title will be replaced -->
<hr>
<div class="message">
<div class="text-container" id="main-content" contenteditable="false"> <!-- Content will be replaced -->
Loading content...
</div>
<div class="qr-code-body">
<div class="qr-code-url">
<span class="url-message">Loading message...</span><br><br> <!-- The message will be replaced -->
<a id="qr-link-2" href="#">Loading...</a> <!-- The href and text will be replaced -->
</div>
<img src="qrcode-content.png" alt="QR Code">
</div>
</div>
<hr>
<div class="footer">
<p>
spread your true voice just like this by filling out <a href="submission_form.pdf">this form</a><br>
and submitting it to <a href="nostr.html">this Nostr Address</a>. We use <a href="https://nostr.how/en/what-is-nostr">Nostr</a>, <a href="https://www.torproject.org/download/">Tor Browser</a>, and <a href="https://wallet.cashu.me/">Cashu eCash</a> to protect your identity.<br>
Your flyer will be hosted on <a href="https://en.wikipedia.org/wiki/Tor_(network)">The Tor Network</a>.<br>
</p>
<p class="credit">built with <a href="https://github.com/PR0M3TH3AN/VoxVera">voxvera</a></p>
<p class="binary" id="binary-message"><br>
<br>Loading...<br> <!-- Binary message will be replaced -->
</p>
</div>
</div>
</div>
<button class="print-button" onclick="window.print()">Print this page</button>
<a class="download-button" href="download/download.zip" download>Download</a>
<script>
// Fetch the configuration JSON file
fetch('config.json')
.then(response => response.json())
.then(config => {
// Update the site title
document.getElementById('site-title').innerText = config.name;
// Update the "Top Secret" title
document.getElementById('top-secret-title').innerText = config.title;
// Update the "DO NOT DISTRIBUTE" message
document.getElementById('do-not-distribute').innerHTML = config.subtitle;
// Update the operation titles
document.getElementById('operation-title-2').innerText = config.headline;
// Update the main content
document.getElementById('main-content').innerText =
config.content.replace(/\\n/g, '\n');
// Update the URL message
document.querySelectorAll('.url-message').forEach(msg => {
msg.innerText = config.url_message;
});
// Update the QR URL link in the main content
document.getElementById('qr-link-2').innerText = config.url;
document.getElementById('qr-link-2').href = config.url;
document.getElementById('qr-link-2').target = "_blank"; // Opens in a new tab
// Update all tear-off links
document.querySelectorAll('.tear-off-link').forEach(link => {
link.innerText = config.tear_off_link;
link.href = config.tear_off_link;
link.target = "_blank"; // Opens in a new tab
});
// Update the binary message
document.getElementById('binary-message').innerText = config.binary_message;
})
.catch(error => console.error('Error loading config:', error));
</script>
</body>
</html>

1
voxvera/src/index.html Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Connect with Me on KeyChat</title>
<style>
body {
font-family: 'Courier New', Courier, monospace;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
background-color: white;
}
.container {
background-color: white;
padding: 20px;
border: 1px solid #000000;
text-align: center;
max-width: 400px;
width: 90%;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
h1 {
color: #333;
}
p {
font-size: 16px;
color: #666;
}
.code-box {
background-color: white;
border: 1px solid #000000;
padding: 10px;
margin: 20px 0;
font-size: 18px;
color: #333;
word-wrap: break-word;
word-break: break-word;
overflow-wrap: break-word;
cursor: pointer;
user-select: none;
}
.copy-btn {
background-color: #000000;
color: white;
padding: 10px 20px;
border: 1px solid #000000;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s ease;
}
.copy-btn:hover {
background-color: #3d3d3d;
}
footer {
margin-top: 20px;
font-size: 14px;
color: #999;
}
.credit {
font-size: 12px;
margin-top: 10px;
}
a {
color: #a30000;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<h1>Nostr</h1>
<p>Use a secure file shareing tool like <a href="https://onionshare.org/" target="_blank">Onion Share</a> or <a href="https://wormhole.app/" target="_blank">WormHole</a> to send your completed <a href="submission_form.pdf" target="_blank">submission form PDF</a> to the following <a href="https://www.0xchat.com/#/" target="_blank">Nostr</a> npub account:</p>
<p></p><a href="index.html">Back to Home</a></p>
<div class="code-box" id="keyChatCode">npub1ln8efl52vsyh6lg59c9v3kut56wev489lzcma0sv2mf8nm6jhwjqeteygt</div>
<button class="copy-btn" onclick="copyCode()">Copy Code</button>
</div>
<footer>
<p>Not on Nostr yet? <a href="https://nostr.how/en/what-is-nostr" target="_blank">Learn more here</a>.</p>
<p class="credit">built with <a href="https://github.com/PR0M3TH3AN/VoxVera">voxvera</a></p>
</footer>
<script>
function copyCode() {
var copyText = document.getElementById("keyChatCode").innerText;
navigator.clipboard.writeText(copyText).then(function() {
alert("Code copied to clipboard!");
}, function(err) {
alert("Failed to copy code: ", err);
});
}
</script>
</body>
</html>

1
voxvera/src/nostr.html Normal file
View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Connect with Me on KeyChat</title><style>body{font-family:'Courier New',Courier,monospace;display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;margin:0;background-color:#fff}.container{background-color:#fff;padding:20px;border:1px solid #000;text-align:center;max-width:400px;width:90%;box-shadow:0 0 10px rgba(0,0,0,.1)}h1{color:#333}p{font-size:16px;color:#666}.code-box{background-color:#fff;border:1px solid #000;padding:10px;margin:20px 0;font-size:18px;color:#333;word-wrap:break-word;word-break:break-word;overflow-wrap:break-word;cursor:pointer;user-select:none}.copy-btn{background-color:#000;color:#fff;padding:10px 20px;border:1px solid #000;cursor:pointer;font-size:16px;transition:background-color .3s ease}.copy-btn:hover{background-color:#3d3d3d}footer{margin-top:20px;font-size:14px;color:#999}.credit{font-size:12px;margin-top:10px}a{color:#a30000;text-decoration:none}a:hover{text-decoration:underline}</style></head><body><div class="container"><h1>Nostr</h1><p>Use a secure file shareing tool like <a href="https://onionshare.org/" target="_blank">Onion Share</a> or <a href="https://wormhole.app/" target="_blank">WormHole</a> to send your completed <a href="submission_form.pdf" target="_blank">submission form PDF</a> to the following <a href="https://www.0xchat.com/#/" target="_blank">Nostr</a> npub account:</p><p></p><a href="index.html">Back to Home</a><p></p><div class="code-box" id="keyChatCode">npub1ln8efl52vsyh6lg59c9v3kut56wev489lzcma0sv2mf8nm6jhwjqeteygt</div><button class="copy-btn" onclick="copyCode()">Copy Code</button></div><footer><p>Not on Nostr yet? <a href="https://nostr.how/en/what-is-nostr" target="_blank">Learn more here</a>.</p><p class="credit">built with <a href="https://github.com/PR0M3TH3AN/VoxVera">voxvera</a></p></footer><script>function a0_0x55b4(){var _0xeeb36b=['Failed\x20to\x20copy\x20code:\x20','36973gPfEDk','3hjGEPG','keyChatCode','clipboard','2471RXzkOy','2005220SDqWBz','then','8464mvqASw','24965hDeypK','468jCVegU','3143720lhnwYU','innerText','Code\x20copied\x20to\x20clipboard!','2722248cDzJJD','9411952bWAcnc','2gKXLTl'];a0_0x55b4=function(){return _0xeeb36b;};return a0_0x55b4();}function a0_0x2f09(_0x591295,_0x18ad6e){var _0x55b435=a0_0x55b4();return a0_0x2f09=function(_0x2f098f,_0x3b879c){_0x2f098f=_0x2f098f-0x103;var _0x38cd8a=_0x55b435[_0x2f098f];return _0x38cd8a;},a0_0x2f09(_0x591295,_0x18ad6e);}(function(_0x460aa5,_0xdd901b){var _0x26f888=a0_0x2f09,_0x58db54=_0x460aa5();while(!![]){try{var _0x40318b=parseInt(_0x26f888(0x10d))/0x1*(parseInt(_0x26f888(0x10b))/0x2)+-parseInt(_0x26f888(0x10e))/0x3*(-parseInt(_0x26f888(0x112))/0x4)+parseInt(_0x26f888(0x104))/0x5*(parseInt(_0x26f888(0x105))/0x6)+parseInt(_0x26f888(0x111))/0x7*(-parseInt(_0x26f888(0x103))/0x8)+parseInt(_0x26f888(0x109))/0x9+parseInt(_0x26f888(0x106))/0xa+-parseInt(_0x26f888(0x10a))/0xb;if(_0x40318b===_0xdd901b)break;else _0x58db54['push'](_0x58db54['shift']());}catch(_0x5c0367){_0x58db54['push'](_0x58db54['shift']());}}}(a0_0x55b4,0x4d04e));function copyCode(){var _0x263cfe=a0_0x2f09,_0x201a80=document['getElementById'](_0x263cfe(0x10f))[_0x263cfe(0x107)];navigator[_0x263cfe(0x110)]['writeText'](_0x201a80)[_0x263cfe(0x113)](function(){var _0x2c37ce=_0x263cfe;alert(_0x2c37ce(0x108));},function(_0x3011e9){var _0x5238cb=_0x263cfe;alert(_0x5238cb(0x10c),_0x3011e9);});}</script></body></html>

View File

@@ -0,0 +1,67 @@
#!/bin/bash
set -euo pipefail
CONFIG_PATH="${1:-config.json}"
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "Error: required command '$1' not found" >&2
exit 1
}
}
for cmd in javascript-obfuscator html-minifier-terser node; do
require_cmd "$cmd"
done
# Detect whether mktemp supports the --suffix option. If not, fall back to a
# portable template-based approach (e.g., on macOS).
if tmp=$(mktemp --suffix=.test 2>/dev/null); then
rm -f "$tmp"
mktemp_with_suffix() { mktemp --suffix="$1"; }
else
mktemp_with_suffix() { mktemp "${TMPDIR:-/tmp}/tmp.XXXXXX$1"; }
fi
# Input and output file names
input_file="index-master.html"
output_file="index.html"
temp_js_file=$(mktemp_with_suffix .js) # Temporary .js file for extracting JavaScript
temp_js_obfuscated_file=$(mktemp_with_suffix .js) # Temporary file for obfuscated JavaScript
temp_html_file=$(mktemp) # Temporary file for processing HTML without JS
# Check if the input file exists
if [ ! -f "$input_file" ]; then
echo "Input file $input_file does not exist."
exit 1
fi
# Extract embedded JavaScript into a temporary .js file
awk '/<script>/,/<\/script>/' "$input_file" | sed '1d;$d' > "$temp_js_file"
# Obfuscate the extracted JavaScript
javascript-obfuscator "$temp_js_file" --output "$temp_js_obfuscated_file"
# Read the obfuscated JavaScript into a variable
obfuscated_js=$(cat "$temp_js_obfuscated_file")
# Escape slashes in the obfuscated JavaScript
escaped_js=$(echo "$obfuscated_js" | sed 's/[\/&]/\\&/g')
# Replace the original JavaScript in the HTML with the obfuscated version
sed -e "/<script>/,/<\/script>/c\<script>$escaped_js<\/script>" "$input_file" > "$temp_html_file"
# Minify HTML, including the obfuscated embedded JavaScript and CSS
html-minifier-terser \
--collapse-whitespace \
--minify-css true \
--remove-comments \
--remove-empty-attributes \
--output "$output_file" \
"$temp_html_file"
# Clean up temporary files
rm "$temp_js_file" "$temp_js_obfuscated_file" "$temp_html_file"
echo "Obfuscation and minification complete. Output saved as $output_file."

View File

@@ -0,0 +1,67 @@
#!/bin/bash
set -euo pipefail
CONFIG_PATH="${1:-config.json}"
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "Error: required command '$1' not found" >&2
exit 1
}
}
for cmd in javascript-obfuscator html-minifier-terser node; do
require_cmd "$cmd"
done
# Detect whether mktemp supports the --suffix option. If not, fall back to a
# portable template-based approach (e.g., on macOS).
if tmp=$(mktemp --suffix=.test 2>/dev/null); then
rm -f "$tmp"
mktemp_with_suffix() { mktemp --suffix="$1"; }
else
mktemp_with_suffix() { mktemp "${TMPDIR:-/tmp}/tmp.XXXXXX$1"; }
fi
# Input and output file names
input_file="nostr-master.html"
output_file="nostr.html"
temp_js_file=$(mktemp_with_suffix .js) # Temporary .js file for extracting JavaScript
temp_js_obfuscated_file=$(mktemp_with_suffix .js) # Temporary file for obfuscated JavaScript
temp_html_file=$(mktemp) # Temporary file for processing HTML without JS
# Check if the input file exists
if [ ! -f "$input_file" ]; then
echo "Input file $input_file does not exist."
exit 1
fi
# Extract embedded JavaScript into a temporary .js file
awk '/<script>/,/<\/script>/' "$input_file" | sed '1d;$d' > "$temp_js_file"
# Obfuscate the extracted JavaScript
javascript-obfuscator "$temp_js_file" --output "$temp_js_obfuscated_file"
# Read the obfuscated JavaScript into a variable
obfuscated_js=$(cat "$temp_js_obfuscated_file")
# Escape slashes in the obfuscated JavaScript
escaped_js=$(echo "$obfuscated_js" | sed 's/[\/&]/\\&/g')
# Replace the original JavaScript in the HTML with the obfuscated version
sed -e "/<script>/,/<\/script>/c\<script>$escaped_js<\/script>" "$input_file" > "$temp_html_file"
# Minify HTML, including the obfuscated embedded JavaScript and CSS
html-minifier-terser \
--collapse-whitespace \
--minify-css true \
--remove-comments \
--remove-empty-attributes \
--output "$output_file" \
"$temp_html_file"
# Clean up temporary files
rm "$temp_js_file" "$temp_js_obfuscated_file" "$temp_html_file"
echo "Obfuscation and minification complete. Output saved as $output_file."

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

2
voxvera/src/to-do.txt Normal file
View File

@@ -0,0 +1,2 @@
1. Make content field smaller max number.
2. URL for content not getting pulled into the config.json correctly every time.

View File

@@ -0,0 +1,117 @@
#!/bin/bash
# Define the input PDF, output text file, and output JSON
pdf_file="./from_client/submission_form.pdf"
text_file="submission_form.txt"
json_file="config.json"
# Log the start of the script
echo "Starting script..."
echo "Looking for PDF at: $pdf_file"
echo "Config JSON: $json_file"
# Convert PDF to text
echo "Converting PDF to text..."
pdftotext -layout "$pdf_file" "$text_file"
# Extract individual fields using grep, logging each step
echo "Extracting fields from the text file..."
# Adjusting the extraction of the name field
name=$(grep -A 3 'name (max 25 characters):' "$text_file" | tail -n 1 | awk '{$1=$1;print}')
echo "Extracted name: '$name'"
subdomain=$(grep -A 1 'subdomain (max 30 characters):' "$text_file" | tail -n 1 | awk '{$1=$1;print}')
echo "Extracted subdomain: '$subdomain'"
title=$(grep -A 1 'title (max 30 characters):' "$text_file" | tail -n 1 | awk '{$1=$1;print}')
echo "Extracted title: '$title'"
subtitle=$(grep -A 1 'subtitle (max 45 characters):' "$text_file" | tail -n 1 | awk '{$1=$1;print}')
echo "Extracted subtitle: '$subtitle'"
headline=$(grep -A 1 'headline (max 50 characters):' "$text_file" | tail -n 1 | awk '{$1=$1;print}')
echo "Extracted headline: '$headline'"
# Process the content to remove soft wraps while keeping hard returns
content=$(grep -A 100 'content (max 1,400 characters):' "$text_file" | sed -n '2,/url_message/p' | sed '$d' | awk '
{
if (NR == 1) {
prev = $0;
next;
}
# Handle paragraph breaks explicitly
if ($0 ~ /^[[:space:]]*$/) {
if (prev) print prev "\n";
prev = "";
}
# Handle sentences that should stay together
else if (prev ~ /[.?!]$/ && $0 ~ /^[[:upper:]]/) {
prev = prev " " $0;
}
# Join lines that are part of the same sentence (soft wrap)
else if (prev !~ /[.?!]$/) {
prev = prev " " $0;
}
# Otherwise, treat as a new sentence/paragraph
else {
if (prev) print prev;
prev = $0;
}
}
END { if (prev) print prev }' | sed -E 's/\n\n[[:space:]]+/\n\n/g' | sed -E 's/^[[:space:]]+//g')
echo "Extracted content: '$content'"
url_message=$(grep -A 1 'url_message (max 60 characters):' "$text_file" | tail -n 1 | awk '{$1=$1;print}')
echo "Extracted url_message: '$url_message'"
url=$(grep -A 1 'url (max 90 characters):' "$text_file" | tail -n 1 | awk '{$1=$1;print}')
echo "Extracted url: '$url'"
# Construct the URLs with the subdomain
onion_base="6dshf2gnj7yzxlfcaczlyi57up4mvbtd5orinuj5bjsfycnhz2w456yd.onion"
constructed_url="http://$subdomain.$onion_base"
# Use an existing tear_off_link from the config if provided; otherwise default
# to the constructed onion URL.
existing_tear_off_link=$(jq -r '.tear_off_link // empty' "$json_file")
tear_off_link="${existing_tear_off_link:-http://$subdomain.$onion_base}"
echo "Constructed URL: '$constructed_url'"
echo "Using Tear-off Link: '$tear_off_link'"
# Check if the extracted fields are not empty
if [ -z "$name" ] || [ -z "$subdomain" ] || [ -z "$title" ] || [ -z "$subtitle" ] || [ -z "$headline" ] || [ -z "$content" ] || [ -z "$url_message" ] || [ -z "$url" ]; then
echo "Error: One or more extracted fields are empty. Please check the PDF form and try again."
exit 1
fi
# Update the JSON using jq and log the operation
echo "Updating config.json..."
jq --arg name "$name" \
--arg subdomain "$subdomain" \
--arg title "$title" \
--arg subtitle "$subtitle" \
--arg headline "$headline" \
--arg content "$content" \
--arg url_message "$url_message" \
--arg url "$url" \
--arg tear_off_link "$tear_off_link" \
'.name = $name |
.subdomain = $subdomain |
.title = $title |
.subtitle = $subtitle |
.headline = $headline |
.content = $content |
.url_message = $url_message |
.url = $url |
.tear_off_link = $tear_off_link' "$json_file" > tmp.json && mv tmp.json "$json_file"
if [ $? -eq 0 ]; then
echo "Config file updated successfully."
else
echo "Error: Failed to update config file."
exit 1
fi

View File

@@ -0,0 +1,12 @@
{
"name": "Vox Vera Printable Flyers",
"subdomain": "voxvera",
"title": "TOP SECRET",
"subtitle": "DO <span class=\\\"redacted\\\">NOT</span> DISTRIBUTE",
"headline": "OPERATION VOX VERA",
"content": "Break free from censorship with VoxVera. An anonymous guerrilla marketing and message-spreading tool. Whether online or in the physical world, it can empower you to spread your ideas boldly, shielded by complete anonymity (if you host over Tor). Download the code, design a flyer site, host it online and amplify your message.\\n\\nUse memetic power to share your ideas in your school, workplace, online communities, or even globally. VoxVera ensures your message resonates far and wide, with tear-off sections featuring unique URLs and QR codes for easy reprinting.\\n\\nPrivacy can be maintained. Flyers can be shared via the Tor network, protecting hoster and users from censorship.\\n\\nJoin us in a revolution that values truth and transparency. Together, we can build a network of informed citizens who are unafraid to speak out.\n",
"url_message": "Follow this link to learn more. Use Tor Browser.",
"url": "https://voxvera.org/",
"tear_off_link": "https://voxvera.org/",
"binary_message": "0110010 0101011 0110010 0111101 0110100"
}

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Connect with Me on KeyChat</title><style>body{font-family:'Courier New',Courier,monospace;display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;margin:0;background-color:#fff}.container{background-color:#fff;padding:20px;border:1px solid #000;text-align:center;max-width:400px;width:90%;box-shadow:0 0 10px rgba(0,0,0,.1)}h1{color:#333}p{font-size:16px;color:#666}.code-box{background-color:#fff;border:1px solid #000;padding:10px;margin:20px 0;font-size:18px;color:#333;word-wrap:break-word;word-break:break-word;overflow-wrap:break-word;cursor:pointer;user-select:none}.copy-btn{background-color:#000;color:#fff;padding:10px 20px;border:1px solid #000;cursor:pointer;font-size:16px;transition:background-color .3s ease}.copy-btn:hover{background-color:#3d3d3d}footer{margin-top:20px;font-size:14px;color:#999}.credit{font-size:12px;margin-top:10px}a{color:#a30000;text-decoration:none}a:hover{text-decoration:underline}</style></head><body><div class="container"><h1>Nostr</h1><p>Use a secure file shareing tool like <a href="https://onionshare.org/" target="_blank">Onion Share</a> or <a href="https://wormhole.app/" target="_blank">WormHole</a> to send your completed <a href="submission_form.pdf" target="_blank">submission form PDF</a> to the following <a href="https://www.0xchat.com/#/" target="_blank">Nostr</a> npub account:</p><p></p><a href="index.html">Back to Home</a><p></p><div class="code-box" id="keyChatCode">npub1ln8efl52vsyh6lg59c9v3kut56wev489lzcma0sv2mf8nm6jhwjqeteygt</div><button class="copy-btn" onclick="copyCode()">Copy Code</button></div><footer><p>Not on Nostr yet? <a href="https://nostr.how/en/what-is-nostr" target="_blank">Learn more here</a>.</p><p class="credit">Flyer generated with <a href="https://github.com/PR0M3TH3AN/VoxVera">Vox Vera</a>.</p></footer><script>function a0_0x55b4(){var _0xeeb36b=['Failed\x20to\x20copy\x20code:\x20','36973gPfEDk','3hjGEPG','keyChatCode','clipboard','2471RXzkOy','2005220SDqWBz','then','8464mvqASw','24965hDeypK','468jCVegU','3143720lhnwYU','innerText','Code\x20copied\x20to\x20clipboard!','2722248cDzJJD','9411952bWAcnc','2gKXLTl'];a0_0x55b4=function(){return _0xeeb36b;};return a0_0x55b4();}function a0_0x2f09(_0x591295,_0x18ad6e){var _0x55b435=a0_0x55b4();return a0_0x2f09=function(_0x2f098f,_0x3b879c){_0x2f098f=_0x2f098f-0x103;var _0x38cd8a=_0x55b435[_0x2f098f];return _0x38cd8a;},a0_0x2f09(_0x591295,_0x18ad6e);}(function(_0x460aa5,_0xdd901b){var _0x26f888=a0_0x2f09,_0x58db54=_0x460aa5();while(!![]){try{var _0x40318b=parseInt(_0x26f888(0x10d))/0x1*(parseInt(_0x26f888(0x10b))/0x2)+-parseInt(_0x26f888(0x10e))/0x3*(-parseInt(_0x26f888(0x112))/0x4)+parseInt(_0x26f888(0x104))/0x5*(parseInt(_0x26f888(0x105))/0x6)+parseInt(_0x26f888(0x111))/0x7*(-parseInt(_0x26f888(0x103))/0x8)+parseInt(_0x26f888(0x109))/0x9+parseInt(_0x26f888(0x106))/0xa+-parseInt(_0x26f888(0x10a))/0xb;if(_0x40318b===_0xdd901b)break;else _0x58db54['push'](_0x58db54['shift']());}catch(_0x5c0367){_0x58db54['push'](_0x58db54['shift']());}}}(a0_0x55b4,0x4d04e));function copyCode(){var _0x263cfe=a0_0x2f09,_0x201a80=document['getElementById'](_0x263cfe(0x10f))[_0x263cfe(0x107)];navigator[_0x263cfe(0x110)]['writeText'](_0x201a80)[_0x263cfe(0x113)](function(){var _0x2c37ce=_0x263cfe;alert(_0x2c37ce(0x108));},function(_0x3011e9){var _0x5238cb=_0x263cfe;alert(_0x5238cb(0x10c),_0x3011e9);});}</script></body></html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.