Add automated versioning and deployment system

This commit is contained in:
Your Name
2025-09-21 11:22:26 -04:00
parent a7dceb1156
commit ea387c0c9f
8 changed files with 446 additions and 42 deletions

3
deploy.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
rsync -avz --progress lite/{nostr-lite.js,nostr.bundle.js} ubuntu@laantungir.net:WWW/nostr-login-lite/

240
examples/keytest.html Normal file
View File

@@ -0,0 +1,240 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Embedded NOSTR_LOGIN_LITE</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
padding: 40px;
background: white;
display: flex;
justify-content: center;
align-items: center;
min-height: 90vh;
}
.container {
max-width: 400px;
width: 100%;
}
#login-container {
/* No styling - let embedded modal blend seamlessly */
}
</style>
</head>
<body>
<div class="container">
<div id="login-container">
<!-- Login interface will appear here -->
</div>
<div id="test-section" style="display: none; margin-top: 30px;">
<h2>Nostr Testing Interface</h2>
<div id="status" style="margin-bottom: 20px; padding: 10px; background: #f0f0f0; border-radius: 5px;"></div>
<div style="display: grid; gap: 15px;">
<button id="sign-button" style="padding: 12px; font-size: 16px; background: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer;">
Sign Event
</button>
<button id="nip04-encrypt-button" style="padding: 12px; font-size: 16px; background: #28a745; color: white; border: none; border-radius: 5px; cursor: pointer;">
NIP-04 Encrypt
</button>
<button id="nip04-decrypt-button" style="padding: 12px; font-size: 16px; background: #28a745; color: white; border: none; border-radius: 5px; cursor: pointer;">
NIP-04 Decrypt
</button>
<button id="nip44-encrypt-button" style="padding: 12px; font-size: 16px; background: #6f42c1; color: white; border: none; border-radius: 5px; cursor: pointer;">
NIP-44 Encrypt
</button>
<button id="nip44-decrypt-button" style="padding: 12px; font-size: 16px; background: #6f42c1; color: white; border: none; border-radius: 5px; cursor: pointer;">
NIP-44 Decrypt
</button>
<button id="get-pubkey-button" style="padding: 12px; font-size: 16px; background: #17a2b8; color: white; border: none; border-radius: 5px; cursor: pointer;">
Get Public Key
</button>
</div>
<div id="results" style="margin-top: 20px; padding: 15px; background: #f8f9fa; border-radius: 5px; font-family: monospace; white-space: pre-wrap; max-height: 400px; overflow-y: auto;"></div>
</div>
</div>
<script src="../lite/nostr.bundle.js"></script>
<script src="../lite/nostr-lite.js"></script>
<script>
document.addEventListener('DOMContentLoaded', async () => {
await window.NOSTR_LOGIN_LITE.init({
theme: 'default',
methods: {
extension: true,
local: true,
seedphrase:true,
readonly: true,
connect: true,
remote: true,
otp: true
},
floatingTab: {
enabled: true,
hPosition: 1, // 0.0-1.0 or '95%' from left
vPosition: 0, // 0.0-1.0 or '50%' from top
appearance: {
style: 'square', // 'pill', 'square', 'circle', 'minimal'
// icon: '[LOGIN]', // Now uses text-based icons like [LOGIN], [KEY], [NET]
text: 'Login'
},
behavior: {
hideWhenAuthenticated: false,
showUserInfo: true,
autoSlide: true
},
animation: {
slideDirection: 'auto' // 'auto', 'left', 'right', 'up', 'down'
}
}});
// Listen for authentication events
window.addEventListener('nlMethodSelected', (event) => {
console.log('User authenticated:', event.detail);
document.getElementById('status').textContent = `Authenticated with: ${event.detail.method}`;
document.getElementById('test-section').style.display = 'block';
// Store some test data for encryption/decryption
window.testCiphertext = null;
window.testCiphertext44 = null;
});
window.addEventListener('nlLogout', () => {
console.log('User logged out');
document.getElementById('status').textContent = 'Logged out';
document.getElementById('test-section').style.display = 'none';
document.getElementById('results').innerHTML = '';
});
// Button event listeners
document.getElementById('get-pubkey-button').addEventListener('click', testGetPublicKey);
document.getElementById('sign-button').addEventListener('click', testSigning);
document.getElementById('nip04-encrypt-button').addEventListener('click', testNip04Encrypt);
document.getElementById('nip04-decrypt-button').addEventListener('click', testNip04Decrypt);
document.getElementById('nip44-encrypt-button').addEventListener('click', testNip44Encrypt);
document.getElementById('nip44-decrypt-button').addEventListener('click', testNip44Decrypt);
});
// Test functions
async function testGetPublicKey() {
try {
updateResults('🔑 Getting public key...');
const pubkey = await window.nostr.getPublicKey();
updateResults(`✅ Public Key: ${pubkey}`);
} catch (error) {
updateResults(`❌ Get Public Key Error: ${error.message}`);
}
}
async function testSigning() {
try {
updateResults('✍️ Signing event...');
const event = {
kind: 1,
content: 'Hello from NOSTR_LOGIN_LITE key test! ' + new Date().toISOString(),
tags: [],
created_at: Math.floor(Date.now() / 1000)
};
const signedEvent = await window.nostr.signEvent(event);
updateResults(`✅ Event Signed Successfully:\n${JSON.stringify(signedEvent, null, 2)}`);
} catch (error) {
updateResults(`❌ Sign Event Error: ${error.message}`);
}
}
async function testNip04Encrypt() {
try {
updateResults('🔐 Testing NIP-04 encryption...');
const pubkey = await window.nostr.getPublicKey();
const plaintext = 'Secret message for NIP-04 testing! ' + Date.now();
const ciphertext = await window.nostr.nip04.encrypt(pubkey, plaintext);
window.testCiphertext = ciphertext; // Store for decryption test
updateResults(`✅ NIP-04 Encrypted:\nPlaintext: ${plaintext}\nCiphertext: ${ciphertext}`);
} catch (error) {
updateResults(`❌ NIP-04 Encrypt Error: ${error.message}`);
}
}
async function testNip04Decrypt() {
try {
if (!window.testCiphertext) {
updateResults('❌ No ciphertext available. Run NIP-04 encrypt first.');
return;
}
updateResults('🔓 Testing NIP-04 decryption...');
const pubkey = await window.nostr.getPublicKey();
const decrypted = await window.nostr.nip04.decrypt(pubkey, window.testCiphertext);
updateResults(`✅ NIP-04 Decrypted:\nCiphertext: ${window.testCiphertext}\nDecrypted: ${decrypted}`);
} catch (error) {
updateResults(`❌ NIP-04 Decrypt Error: ${error.message}`);
}
}
async function testNip44Encrypt() {
try {
updateResults('🔐 Testing NIP-44 encryption...');
const pubkey = await window.nostr.getPublicKey();
const plaintext = 'Secret message for NIP-44 testing! ' + Date.now();
const ciphertext = await window.nostr.nip44.encrypt(pubkey, plaintext);
window.testCiphertext44 = ciphertext; // Store for decryption test
updateResults(`✅ NIP-44 Encrypted:\nPlaintext: ${plaintext}\nCiphertext: ${ciphertext}`);
} catch (error) {
updateResults(`❌ NIP-44 Encrypt Error: ${error.message}`);
}
}
async function testNip44Decrypt() {
try {
if (!window.testCiphertext44) {
updateResults('❌ No ciphertext available. Run NIP-44 encrypt first.');
return;
}
updateResults('🔓 Testing NIP-44 decryption...');
const pubkey = await window.nostr.getPublicKey();
const decrypted = await window.nostr.nip44.decrypt(pubkey, window.testCiphertext44);
updateResults(`✅ NIP-44 Decrypted:\nCiphertext: ${window.testCiphertext44}\nDecrypted: ${decrypted}`);
} catch (error) {
updateResults(`❌ NIP-44 Decrypt Error: ${error.message}`);
}
}
function updateResults(message) {
const results = document.getElementById('results');
const timestamp = new Date().toLocaleTimeString();
results.textContent += `[${timestamp}] ${message}\n\n`;
results.scrollTop = results.scrollHeight;
}
</script>
</body>
</html>

View File

@@ -49,6 +49,8 @@
try {
await window.NOSTR_LOGIN_LITE.init({
persistence: true, // Enable persistent authentication (default: true)
isolateSession: true, // Use sessionStorage for per-tab isolation (default: false = localStorage)
theme: 'default',
darkMode: false,
methods: {

107
increment_build_push.sh Executable file
View File

@@ -0,0 +1,107 @@
#!/bin/bash
# increment_build_push.sh
# Automates version increment, build, and git operations
set -e # Exit on any error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}🔄 Starting increment, build, and push process...${NC}"
# Function to get the latest git tag
get_latest_tag() {
# Get the latest tag that matches the pattern v*.*.*
git tag -l "v*.*.*" | sort -V | tail -n1
}
# Function to increment version
increment_version() {
local version=$1
# Remove 'v' prefix if present
version=${version#v}
# Split version into parts
IFS='.' read -ra VERSION_PARTS <<< "$version"
# Increment the patch version (last digit)
local major=${VERSION_PARTS[0]}
local minor=${VERSION_PARTS[1]}
local patch=${VERSION_PARTS[2]}
patch=$((patch + 1))
echo "$major.$minor.$patch"
}
# Step 1: Get current version
echo -e "${YELLOW}📋 Getting current version...${NC}"
current_tag=$(get_latest_tag)
if [ -z "$current_tag" ]; then
echo -e "${YELLOW}⚠️ No existing version tags found, starting with v0.1.0${NC}"
current_version="0.1.0"
else
echo -e "Current tag: ${current_tag}"
current_version=${current_tag#v}
fi
# Step 2: Increment version
new_version=$(increment_version "$current_version")
new_tag="v$new_version"
echo -e "${GREEN}📈 Incrementing version: $current_version$new_version${NC}"
# Step 2.5: Save version to lite/VERSION file
echo -e "${YELLOW}💾 Saving version to lite/VERSION...${NC}"
echo "$new_version" > lite/VERSION
echo -e "Version saved: ${GREEN}$new_version${NC}"
# Step 2.5: Run build.js
echo -e "${YELLOW}🔧 Running build process...${NC}"
cd lite
node build.js
cd ..
echo -e "${GREEN}✅ Build completed${NC}"
# Step 3: Git add
echo -e "${YELLOW}📦 Adding files to git...${NC}"
git add .
# Step 4: Handle commit message and commit
commit_message=""
if [ $# -eq 0 ]; then
# No arguments provided, ask for commit message
echo -e "${YELLOW}💬 Please enter a commit message:${NC}"
read -p "> " commit_message
if [ -z "$commit_message" ]; then
echo -e "${RED}❌ Commit message cannot be empty${NC}"
exit 1
fi
else
# Use provided arguments as commit message
commit_message="$*"
fi
echo -e "${YELLOW}💬 Committing changes...${NC}"
git commit -m "$commit_message"
echo -e "${YELLOW}🏷️ Creating git tag: $new_tag${NC}"
git tag "$new_tag"
# Step 5: Git push
echo -e "${YELLOW}🚀 Pushing to remote...${NC}"
git push
git push --tags
echo -e "${GREEN}🎉 Successfully completed:${NC}"
echo -e " • Version incremented to: ${GREEN}$new_version${NC}"
echo -e " • VERSION file updated: ${GREEN}lite/VERSION${NC}"
echo -e " • Build completed: ${GREEN}lite/nostr-lite.js${NC}"
echo -e " • Git tag created: ${GREEN}$new_tag${NC}"
echo -e " • Changes pushed to remote${NC}"
echo -e "\n${GREEN}✨ Process complete!${NC}"

1
lite/VERSION Normal file
View File

@@ -0,0 +1 @@
0.1.3

View File

@@ -131,6 +131,25 @@ if (typeof window !== 'undefined') {
let modalContent = fs.readFileSync(modalPath, 'utf8');
// Read version from VERSION file and inject into modal title
const versionPath = path.join(__dirname, 'VERSION');
let versionTitle = 'Nostr Login';
if (fs.existsSync(versionPath)) {
try {
const version = fs.readFileSync(versionPath, 'utf8').trim();
versionTitle = `Nostr Login v${version}`;
console.log(`🔢 Using version: ${version}`);
} catch (error) {
console.warn('⚠️ Could not read VERSION file, using default title');
}
} else {
console.log('📋 No VERSION file found, using default title');
}
// Replace the modal title in the content
modalContent = modalContent.replace(/modalTitle\.textContent = 'Nostr Login';/, `modalTitle.textContent = '${versionTitle}';`);
// Skip header comments
let lines = modalContent.split('\n');
let contentStartIndex = 0;

View File

@@ -8,7 +8,7 @@
* Two-file architecture:
* 1. Load nostr.bundle.js (official nostr-tools bundle)
* 2. Load nostr-lite.js (this file - NOSTR_LOGIN_LITE library with CSS-only themes)
* Generated on: 2025-09-20T19:25:01.143Z
* Generated on: 2025-09-21T15:22:26.408Z
*/
// Verify dependencies are loaded
@@ -381,7 +381,7 @@ class Modal {
`;
const modalTitle = document.createElement('h2');
modalTitle.textContent = 'Nostr Login';
modalTitle.textContent = 'Nostr Login v0.1.3';
modalTitle.style.cssText = `
margin: 0;
font-size: 24px;
@@ -1253,24 +1253,28 @@ class Modal {
nsecLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
const nsecContainer = document.createElement('div');
nsecContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;';
nsecContainer.style.cssText = 'margin-bottom: 8px;';
const nsecCode = document.createElement('code');
nsecCode.textContent = nsec;
nsecCode.style.cssText = `
flex: 1;
word-break: break-all;
display: block;
word-wrap: break-word;
overflow-wrap: break-word;
background: #f3f4f6;
padding: 6px;
border-radius: 4px;
font-size: 10px;
line-height: 1.3;
font-family: 'Courier New', monospace;
display: block;
margin-bottom: 4px;
`;
const nsecCopyBtn = createCopyButton(nsec, 'nsec');
nsecCopyBtn.style.cssText += 'display: inline-block; margin-left: 0;';
nsecContainer.appendChild(nsecCode);
nsecContainer.appendChild(createCopyButton(nsec, 'nsec'));
nsecContainer.appendChild(nsecCopyBtn);
nsecSection.appendChild(nsecLabel);
nsecSection.appendChild(nsecContainer);
@@ -1281,24 +1285,28 @@ class Modal {
secretHexLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
const secretHexContainer = document.createElement('div');
secretHexContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;';
secretHexContainer.style.cssText = 'margin-bottom: 8px;';
const secretHexCode = document.createElement('code');
secretHexCode.textContent = secretKeyHex;
secretHexCode.style.cssText = `
flex: 1;
word-break: break-all;
display: block;
word-wrap: break-word;
overflow-wrap: break-word;
background: #f3f4f6;
padding: 6px;
border-radius: 4px;
font-size: 10px;
line-height: 1.3;
font-family: 'Courier New', monospace;
display: block;
margin-bottom: 4px;
`;
const secretHexCopyBtn = createCopyButton(secretKeyHex, 'hex');
secretHexCopyBtn.style.cssText += 'display: inline-block; margin-left: 0;';
secretHexContainer.appendChild(secretHexCode);
secretHexContainer.appendChild(createCopyButton(secretKeyHex, 'hex'));
secretHexContainer.appendChild(secretHexCopyBtn);
nsecSection.appendChild(secretHexLabel);
nsecSection.appendChild(secretHexContainer);
}
@@ -1314,24 +1322,28 @@ class Modal {
npubLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
const npubContainer = document.createElement('div');
npubContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;';
npubContainer.style.cssText = 'margin-bottom: 8px;';
const npubCode = document.createElement('code');
npubCode.textContent = npub;
npubCode.style.cssText = `
flex: 1;
word-break: break-all;
display: block;
word-wrap: break-word;
overflow-wrap: break-word;
background: #f3f4f6;
padding: 6px;
border-radius: 4px;
font-size: 10px;
line-height: 1.3;
font-family: 'Courier New', monospace;
display: block;
margin-bottom: 4px;
`;
const npubCopyBtn = createCopyButton(npub, 'npub');
npubCopyBtn.style.cssText += 'display: inline-block; margin-left: 0;';
npubContainer.appendChild(npubCode);
npubContainer.appendChild(createCopyButton(npub, 'npub'));
npubContainer.appendChild(npubCopyBtn);
npubSection.appendChild(npubLabel);
npubSection.appendChild(npubContainer);
@@ -1341,24 +1353,28 @@ class Modal {
pubHexLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
const pubHexContainer = document.createElement('div');
pubHexContainer.style.cssText = 'display: flex; align-items: flex-start;';
pubHexContainer.style.cssText = '';
const pubHexCode = document.createElement('code');
pubHexCode.textContent = pubkeyHex;
pubHexCode.style.cssText = `
flex: 1;
word-break: break-all;
display: block;
word-wrap: break-word;
overflow-wrap: break-word;
background: #f3f4f6;
padding: 6px;
border-radius: 4px;
font-size: 10px;
line-height: 1.3;
font-family: 'Courier New', monospace;
display: block;
margin-bottom: 4px;
`;
const pubHexCopyBtn = createCopyButton(pubkeyHex, 'hex');
pubHexCopyBtn.style.cssText += 'display: inline-block; margin-left: 0;';
pubHexContainer.appendChild(pubHexCode);
pubHexContainer.appendChild(createCopyButton(pubkeyHex, 'hex'));
pubHexContainer.appendChild(pubHexCopyBtn);
npubSection.appendChild(pubHexLabel);
npubSection.appendChild(pubHexContainer);

View File

@@ -956,24 +956,28 @@ class Modal {
nsecLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
const nsecContainer = document.createElement('div');
nsecContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;';
nsecContainer.style.cssText = 'margin-bottom: 8px;';
const nsecCode = document.createElement('code');
nsecCode.textContent = nsec;
nsecCode.style.cssText = `
flex: 1;
word-break: break-all;
display: block;
word-wrap: break-word;
overflow-wrap: break-word;
background: #f3f4f6;
padding: 6px;
border-radius: 4px;
font-size: 10px;
line-height: 1.3;
font-family: 'Courier New', monospace;
display: block;
margin-bottom: 4px;
`;
const nsecCopyBtn = createCopyButton(nsec, 'nsec');
nsecCopyBtn.style.cssText += 'display: inline-block; margin-left: 0;';
nsecContainer.appendChild(nsecCode);
nsecContainer.appendChild(createCopyButton(nsec, 'nsec'));
nsecContainer.appendChild(nsecCopyBtn);
nsecSection.appendChild(nsecLabel);
nsecSection.appendChild(nsecContainer);
@@ -984,24 +988,28 @@ class Modal {
secretHexLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
const secretHexContainer = document.createElement('div');
secretHexContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;';
secretHexContainer.style.cssText = 'margin-bottom: 8px;';
const secretHexCode = document.createElement('code');
secretHexCode.textContent = secretKeyHex;
secretHexCode.style.cssText = `
flex: 1;
word-break: break-all;
display: block;
word-wrap: break-word;
overflow-wrap: break-word;
background: #f3f4f6;
padding: 6px;
border-radius: 4px;
font-size: 10px;
line-height: 1.3;
font-family: 'Courier New', monospace;
display: block;
margin-bottom: 4px;
`;
const secretHexCopyBtn = createCopyButton(secretKeyHex, 'hex');
secretHexCopyBtn.style.cssText += 'display: inline-block; margin-left: 0;';
secretHexContainer.appendChild(secretHexCode);
secretHexContainer.appendChild(createCopyButton(secretKeyHex, 'hex'));
secretHexContainer.appendChild(secretHexCopyBtn);
nsecSection.appendChild(secretHexLabel);
nsecSection.appendChild(secretHexContainer);
}
@@ -1017,24 +1025,28 @@ class Modal {
npubLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
const npubContainer = document.createElement('div');
npubContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;';
npubContainer.style.cssText = 'margin-bottom: 8px;';
const npubCode = document.createElement('code');
npubCode.textContent = npub;
npubCode.style.cssText = `
flex: 1;
word-break: break-all;
display: block;
word-wrap: break-word;
overflow-wrap: break-word;
background: #f3f4f6;
padding: 6px;
border-radius: 4px;
font-size: 10px;
line-height: 1.3;
font-family: 'Courier New', monospace;
display: block;
margin-bottom: 4px;
`;
const npubCopyBtn = createCopyButton(npub, 'npub');
npubCopyBtn.style.cssText += 'display: inline-block; margin-left: 0;';
npubContainer.appendChild(npubCode);
npubContainer.appendChild(createCopyButton(npub, 'npub'));
npubContainer.appendChild(npubCopyBtn);
npubSection.appendChild(npubLabel);
npubSection.appendChild(npubContainer);
@@ -1044,24 +1056,28 @@ class Modal {
pubHexLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
const pubHexContainer = document.createElement('div');
pubHexContainer.style.cssText = 'display: flex; align-items: flex-start;';
pubHexContainer.style.cssText = '';
const pubHexCode = document.createElement('code');
pubHexCode.textContent = pubkeyHex;
pubHexCode.style.cssText = `
flex: 1;
word-break: break-all;
display: block;
word-wrap: break-word;
overflow-wrap: break-word;
background: #f3f4f6;
padding: 6px;
border-radius: 4px;
font-size: 10px;
line-height: 1.3;
font-family: 'Courier New', monospace;
display: block;
margin-bottom: 4px;
`;
const pubHexCopyBtn = createCopyButton(pubkeyHex, 'hex');
pubHexCopyBtn.style.cssText += 'display: inline-block; margin-left: 0;';
pubHexContainer.appendChild(pubHexCode);
pubHexContainer.appendChild(createCopyButton(pubkeyHex, 'hex'));
pubHexContainer.appendChild(pubHexCopyBtn);
npubSection.appendChild(pubHexLabel);
npubSection.appendChild(pubHexContainer);