qr-secure-send 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.html +64 -9
  2. package/package.json +1 -1
package/index.html CHANGED
@@ -124,6 +124,7 @@
124
124
  <header>
125
125
  <h1>QR Secure Send</h1>
126
126
  <p>Encrypt and transfer secrets via QR code</p>
127
+ <p style="font-size:0.7rem;color:#484f58;margin-top:0.2rem">v1.5.0</p>
127
128
  </header>
128
129
 
129
130
  <div class="tabs">
@@ -168,7 +169,9 @@
168
169
  <div class="btn-row">
169
170
  <button class="primary" id="scan-btn">Start Camera</button>
170
171
  <button class="secondary" id="stop-btn" style="display:none">Stop</button>
172
+ <button class="primary" id="decrypt-btn" style="display:none">Decrypt</button>
171
173
  </div>
174
+ <div id="link-notice" class="info" style="display:none">Encrypted data received via link. Enter the passphrase and click Decrypt.</div>
172
175
  <div id="recv-error" class="error"></div>
173
176
  <div id="compat-warning" class="warning" style="display:none"></div>
174
177
  </div>
@@ -356,7 +359,7 @@
356
359
  // -- QR matrix construction --
357
360
 
358
361
  const ALIGNMENT_POSITIONS = [
359
- null,[],[], [6,22],[6,26],[6,30],[6,34],
362
+ null,[],[6,18], [6,22],[6,26],[6,30],[6,34],
360
363
  [6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],
361
364
  [6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],
362
365
  [6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],
@@ -621,15 +624,15 @@
621
624
  ];
622
625
  for (let i = 0; i < 15; i++) {
623
626
  const [r, c] = positions1[i];
624
- matrix[r][c] = ((bits >> (14 - i)) & 1) ? 1 : 2;
627
+ matrix[r][c] = ((bits >> i) & 1) ? 1 : 2;
625
628
  }
626
629
 
627
- // Bottom-left and top-right
630
+ // Bottom-left and top-right (opposite bit order from first copy)
628
631
  for (let i = 0; i < 7; i++) {
629
- matrix[size - 1 - i][8] = ((bits >> i) & 1) ? 1 : 2;
632
+ matrix[size - 1 - i][8] = ((bits >> (14 - i)) & 1) ? 1 : 2;
630
633
  }
631
634
  for (let i = 7; i < 15; i++) {
632
- matrix[8][size - 15 + i] = ((bits >> i) & 1) ? 1 : 2;
635
+ matrix[8][size - 15 + i] = ((bits >> (14 - i)) & 1) ? 1 : 2;
633
636
  }
634
637
  }
635
638
 
@@ -905,6 +908,22 @@
905
908
  }
906
909
 
907
910
 
911
+ // =========================================================================
912
+ // PAYLOAD HELPERS
913
+ // =========================================================================
914
+
915
+ const GH_PAGES_URL = "https://degenddy.github.io/qr-secure-send/";
916
+
917
+ // Extract the base64 encrypted data from either raw "QRSEC:..." or a URL with "#QRSEC:..."
918
+ function extractPayload(text) {
919
+ if (text.startsWith("QRSEC:")) return text.slice(6);
920
+ try {
921
+ const hash = new URL(text).hash;
922
+ if (hash.startsWith("#QRSEC:")) return hash.slice(7);
923
+ } catch (_) {}
924
+ return null;
925
+ }
926
+
908
927
  // =========================================================================
909
928
  // UI LOGIC
910
929
  // =========================================================================
@@ -950,10 +969,10 @@
950
969
 
951
970
  try {
952
971
  const encrypted = await encryptSecret(secret, passphrase);
953
- const payload = "QRSEC:" + encrypted;
972
+ const payload = GH_PAGES_URL + "#QRSEC:" + encrypted;
954
973
 
955
974
  if (payload.length > 2953) {
956
- errEl.textContent = "Secret is too long for a QR code. Keep it under ~2000 characters.";
975
+ errEl.textContent = "Secret is too long for a QR code. Keep it under ~1950 characters.";
957
976
  return;
958
977
  }
959
978
 
@@ -991,12 +1010,13 @@
991
1010
  const started = await QRScan.start(
992
1011
  region,
993
1012
  async (decodedText) => {
994
- if (!decodedText.startsWith("QRSEC:")) {
1013
+ const encrypted = extractPayload(decodedText);
1014
+ if (!encrypted) {
995
1015
  errEl.textContent = "Not a QR Secure Send code.";
996
1016
  return false; // keep scanning
997
1017
  }
998
1018
  try {
999
- const secret = await decryptSecret(decodedText.slice(6), passphrase);
1019
+ const secret = await decryptSecret(encrypted, passphrase);
1000
1020
  document.getElementById("recv-value").textContent = secret;
1001
1021
  resultBox.style.display = "block";
1002
1022
  errEl.textContent = "";
@@ -1028,6 +1048,41 @@
1028
1048
  document.getElementById("stop-btn").style.display = "none";
1029
1049
  });
1030
1050
 
1051
+ // Decrypt button (for link-based flow)
1052
+ document.getElementById("decrypt-btn").addEventListener("click", async () => {
1053
+ const passphrase = document.getElementById("recv-passphrase").value;
1054
+ const errEl = document.getElementById("recv-error");
1055
+ const resultBox = document.getElementById("recv-result");
1056
+ errEl.textContent = "";
1057
+ resultBox.style.display = "none";
1058
+
1059
+ if (!passphrase) { errEl.textContent = "Enter the decryption passphrase first."; return; }
1060
+
1061
+ const hashData = location.hash.startsWith("#QRSEC:") ? location.hash.slice(7) : null;
1062
+ if (!hashData) { errEl.textContent = "No encrypted data found in URL."; return; }
1063
+
1064
+ try {
1065
+ const secret = await decryptSecret(hashData, passphrase);
1066
+ document.getElementById("recv-value").textContent = secret;
1067
+ resultBox.style.display = "block";
1068
+ } catch (e) {
1069
+ errEl.textContent = "Decryption failed. Wrong passphrase?";
1070
+ }
1071
+ });
1072
+
1073
+ // Check URL hash for incoming encrypted data (link-based receive flow)
1074
+ if (location.hash.startsWith("#QRSEC:")) {
1075
+ // Switch to receive tab
1076
+ document.querySelectorAll(".tab-btn").forEach(b => b.classList.remove("active"));
1077
+ document.querySelectorAll(".panel").forEach(p => p.classList.remove("active"));
1078
+ document.querySelector('[data-tab="receive"]').classList.add("active");
1079
+ document.getElementById("receive").classList.add("active");
1080
+ // Show decrypt button instead of camera controls
1081
+ document.getElementById("scan-btn").style.display = "none";
1082
+ document.getElementById("decrypt-btn").style.display = "inline-block";
1083
+ document.getElementById("link-notice").style.display = "block";
1084
+ }
1085
+
1031
1086
  // Copy to clipboard
1032
1087
  document.getElementById("copy-btn").addEventListener("click", async () => {
1033
1088
  const value = document.getElementById("recv-value").textContent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qr-secure-send",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Encrypt and transfer secrets via QR code",
5
5
  "keywords": ["qr", "qrcode", "encryption", "password", "secure", "transfer"],
6
6
  "author": "",