@@ -2,11 +2,13 @@ package keygenfunction
22
33import (
44 "encoding/base64"
5+ "encoding/hex"
56 "encoding/json"
67 "fmt"
78 "html/template"
89 "net/http"
910 "os"
11+ "time"
1012
1113 "aidanwoods.dev/go-paseto"
1214 "github.com/GoogleCloudPlatform/functions-framework-go/functions"
@@ -17,8 +19,17 @@ func init() {
1719}
1820
1921type KeyPair struct {
20- PrivateKey string `json:"privateKey"`
21- PublicKey string `json:"publicKey"`
22+ PrivateKey KeyData `json:"privateKey"`
23+ PublicKey KeyData `json:"publicKey"`
24+ GeneratedAt time.Time `json:"generatedAt"`
25+ KeyType string `json:"keyType"`
26+ Algorithm string `json:"algorithm"`
27+ }
28+
29+ type KeyData struct {
30+ Base64 string `json:"base64"`
31+ Hex string `json:"hex"`
32+ ByteLength int `json:"byteLength"`
2233}
2334
2435// KeygenHandler serves both the HTML page and handles key generation
@@ -105,14 +116,25 @@ func generateKeys(w http.ResponseWriter, r *http.Request) {
105116 secretKey := paseto .NewV4AsymmetricSecretKey ()
106117 publicKey := secretKey .Public ()
107118
108- // Convert keys to base64 for storage
109- privateKeyBase64 := base64 . StdEncoding . EncodeToString ( secretKey .ExportBytes () )
110- publicKeyBase64 := base64 . StdEncoding . EncodeToString ( publicKey .ExportBytes () )
119+ // Export raw bytes
120+ privateKeyBytes := secretKey .ExportBytes ()
121+ publicKeyBytes := publicKey .ExportBytes ()
111122
112- // Create response
123+ // Create response with multiple encoding formats
113124 keyPair := KeyPair {
114- PrivateKey : privateKeyBase64 ,
115- PublicKey : publicKeyBase64 ,
125+ PrivateKey : KeyData {
126+ Base64 : base64 .StdEncoding .EncodeToString (privateKeyBytes ),
127+ Hex : hex .EncodeToString (privateKeyBytes ),
128+ ByteLength : len (privateKeyBytes ),
129+ },
130+ PublicKey : KeyData {
131+ Base64 : base64 .StdEncoding .EncodeToString (publicKeyBytes ),
132+ Hex : hex .EncodeToString (publicKeyBytes ),
133+ ByteLength : len (publicKeyBytes ),
134+ },
135+ GeneratedAt : time .Now ().UTC (),
136+ KeyType : "asymmetric" ,
137+ Algorithm : "PASETO v4" ,
116138 }
117139
118140 // Set response headers
@@ -346,6 +368,50 @@ const htmlTemplate = `
346368 margin-top: 20px;
347369 color: #721c24;
348370 }
371+
372+ .key-metadata {
373+ background: #e3f2fd;
374+ border-radius: 8px;
375+ padding: 15px;
376+ margin-bottom: 20px;
377+ border-left: 4px solid #2196f3;
378+ }
379+
380+ .key-metadata p {
381+ margin: 5px 0;
382+ color: #1565c0;
383+ }
384+
385+ .format-tabs {
386+ display: flex;
387+ margin-bottom: 10px;
388+ border-bottom: 1px solid #dee2e6;
389+ }
390+
391+ .format-tab {
392+ background: transparent;
393+ border: none;
394+ padding: 8px 16px;
395+ cursor: pointer;
396+ border-bottom: 2px solid transparent;
397+ color: #666;
398+ font-weight: 500;
399+ transition: all 0.2s;
400+ }
401+
402+ .format-tab:hover {
403+ color: #667eea;
404+ }
405+
406+ .format-tab.active {
407+ color: #667eea;
408+ border-bottom-color: #667eea;
409+ }
410+
411+ .key-info {
412+ margin-top: 8px;
413+ color: #666;
414+ }
349415 </style>
350416</head>
351417<body>
@@ -374,19 +440,47 @@ const htmlTemplate = `
374440 </div>
375441
376442 <div class="results" id="results">
443+ <div class="key-metadata" id="key-metadata">
444+ <p><strong>Generated:</strong> <span id="generated-at"></span></p>
445+ <p><strong>Algorithm:</strong> <span id="algorithm"></span></p>
446+ <p><strong>Type:</strong> <span id="key-type"></span></p>
447+ </div>
448+
377449 <div class="key-section private">
378450 <h3>Private Key</h3>
379- <div class="key-display" id="private-key">
380- <button class="copy-btn" onclick="copyToClipboard('private-key-text', this)">Copy</button>
381- <span id="private-key-text"></span>
451+ <div class="format-tabs">
452+ <button class="format-tab active" onclick="switchFormat('private', 'base64')">Base64</button>
453+ <button class="format-tab" onclick="switchFormat('private', 'hex')">Hex</button>
454+ </div>
455+ <div class="key-display" id="private-key-base64">
456+ <button class="copy-btn" onclick="copyToClipboard('private-key-base64-text', this)">Copy</button>
457+ <span id="private-key-base64-text"></span>
458+ </div>
459+ <div class="key-display" id="private-key-hex" style="display: none;">
460+ <button class="copy-btn" onclick="copyToClipboard('private-key-hex-text', this)">Copy</button>
461+ <span id="private-key-hex-text"></span>
462+ </div>
463+ <div class="key-info">
464+ <small>Length: <span id="private-key-length"></span> bytes</small>
382465 </div>
383466 </div>
384467
385468 <div class="key-section public">
386469 <h3>Public Key</h3>
387- <div class="key-display" id="public-key">
388- <button class="copy-btn" onclick="copyToClipboard('public-key-text', this)">Copy</button>
389- <span id="public-key-text"></span>
470+ <div class="format-tabs">
471+ <button class="format-tab active" onclick="switchFormat('public', 'base64')">Base64</button>
472+ <button class="format-tab" onclick="switchFormat('public', 'hex')">Hex</button>
473+ </div>
474+ <div class="key-display" id="public-key-base64">
475+ <button class="copy-btn" onclick="copyToClipboard('public-key-base64-text', this)">Copy</button>
476+ <span id="public-key-base64-text"></span>
477+ </div>
478+ <div class="key-display" id="public-key-hex" style="display: none;">
479+ <button class="copy-btn" onclick="copyToClipboard('public-key-hex-text', this)">Copy</button>
480+ <span id="public-key-hex-text"></span>
481+ </div>
482+ <div class="key-info">
483+ <small>Length: <span id="public-key-length"></span> bytes</small>
390484 </div>
391485 </div>
392486
@@ -424,9 +518,20 @@ const htmlTemplate = `
424518
425519 const data = await response.json();
426520
427- // Display the keys
428- document.getElementById('private-key-text').textContent = data.privateKey;
429- document.getElementById('public-key-text').textContent = data.publicKey;
521+ // Display metadata
522+ document.getElementById('generated-at').textContent = new Date(data.generatedAt).toLocaleString();
523+ document.getElementById('algorithm').textContent = data.algorithm;
524+ document.getElementById('key-type').textContent = data.keyType;
525+
526+ // Display private key data
527+ document.getElementById('private-key-base64-text').textContent = data.privateKey.base64;
528+ document.getElementById('private-key-hex-text').textContent = data.privateKey.hex;
529+ document.getElementById('private-key-length').textContent = data.privateKey.byteLength;
530+
531+ // Display public key data
532+ document.getElementById('public-key-base64-text').textContent = data.publicKey.base64;
533+ document.getElementById('public-key-hex-text').textContent = data.publicKey.hex;
534+ document.getElementById('public-key-length').textContent = data.publicKey.byteLength;
430535
431536 // Show results
432537 loading.style.display = 'none';
@@ -485,6 +590,25 @@ const htmlTemplate = `
485590 }
486591 }
487592
593+ function switchFormat(keyType, format) {
594+ // Update tab states
595+ const tabs = document.querySelectorAll(` + "`" + `.key-section.${keyType} .format-tab` + "`" + `);
596+ tabs.forEach(tab => tab.classList.remove('active'));
597+ event.target.classList.add('active');
598+
599+ // Show/hide content
600+ const base64Display = document.getElementById(` + "`" + `${keyType}-key-base64` + "`" + `);
601+ const hexDisplay = document.getElementById(` + "`" + `${keyType}-key-hex` + "`" + `);
602+
603+ if (format === 'base64') {
604+ base64Display.style.display = 'block';
605+ hexDisplay.style.display = 'none';
606+ } else {
607+ base64Display.style.display = 'none';
608+ hexDisplay.style.display = 'block';
609+ }
610+ }
611+
488612 // Generate keys on page load for demo
489613 window.addEventListener('load', () => {
490614 // Uncomment the line below if you want to auto-generate keys on page load
0 commit comments