JavaScript köprü API'si
Biyometri ve anahtar deposu
Parmak izi ve yüz ile kilit açma ve sayfanın şifrelemede kullanabildiği ama asla okuyamadığı donanım destekli anahtarlar.
AppMintKeystore.decrypt yardımcı#
window.AppMintKeystore.decrypt(alias, base64)
Örnek
AppMintKeystore.encrypt ile aynı anahtarla oluşturulan verilerin şifresini çözer.
Döndürür: hemen bir nesne (Promise değil): {ok:true, base64} (düz veri) veya {ok:false, error, detail}. Gerekli: derleme yaparken Güvenli Anahtarlar (şifreleme) açık.
function fromBase64(b64) { return decodeURIComponent(escape(atob(b64))); }
function readSecret() {
var sealed = localStorage.getItem('secret');
if (!sealed || !window.AppMintKeystore) return null;
var r = window.AppMintKeystore.decrypt('vault', sealed);
if (r.ok) return fromBase64(r.base64);
switch (r.error) {
case 'auth-required': unlockThen(readSecretAndShow); break; // unlock, then try again
case 'no-such-key':
case 'key-invalidated': alert('This secret can no longer be opened.'); break;
default: alert('Could not decrypt: ' + r.error);
}
return null;
}WebToApkFS.writeSealed ile yazılan bir dosyayı WebToApkFS.readSealed(path, alias) ile geri okuyun - sonuç biçimi aynıdır.
Mühürlü bir JSON nesnesini geri okuyun; anahtar gerektiriyorsa önce kilidi açın:
function unlock() {
return new Promise(function (resolve) {
var id = 'unlock_' + Date.now();
window.__webToApkAuth = window.__webToApkAuth || {};
window.__webToApkAuth[id] = function (json) { resolve(JSON.parse(json)); };
window.WebToApk.authenticateBiometricEx(id, JSON.stringify({
title: 'Unlock your settings', strong: true, allowDeviceCredential: true
}));
});
}
async function loadSealedSettings() {
var sealed = localStorage.getItem('settings');
if (!sealed || !window.AppMintKeystore || !window.AppMintKeystore.isAvailable()) return null;
var r = window.AppMintKeystore.decrypt('vault', sealed);
if (!r.ok && r.error === 'auth-required' && (await unlock()).ok) {
r = window.AppMintKeystore.decrypt('vault', sealed);
}
return r.ok ? JSON.parse(decodeURIComponent(escape(atob(r.base64)))) : null;
}Mühürlü günlük kayıtlarının bir listesini açın, başarısız olanları "kilitli" olarak görünür tutun:
function loadDiary() {
if (!window.AppMintKeystore || !window.AppMintKeystore.isAvailable()) return [];
var entries = JSON.parse(localStorage.getItem('diary') || '[]'); // [{date, sealed}]
return entries.map(function (e) {
var r = window.AppMintKeystore.decrypt('diary', e.sealed);
return {
date: e.date,
text: r.ok ? decodeURIComponent(escape(atob(r.base64))) : null,
error: r.ok ? null : r.error // e.g. 'auth-required', 'no-such-key'
};
});
}Notlar: deleteKey sonrasında veri kalıcı olarak gider; amaç da budur. Değiştirilmiş bir yük GCM denetiminden geçemez. Diğer hatalar: bad base64, disabled, foreign_origin, unsupported.
AppMintKeystore.deleteKey yardımcı#
window.AppMintKeystore.deleteKey(alias)
Örnek
Güvenli bir anahtarı kalıcı olarak yok eder. Onunla şifrelenen her şey bir daha kimse tarafından okunamaz.
Döndürür: hemen true (silindi) veya false (böyle bir anahtar yok ya da özellik kapalı). Gerekli: derleme yaparken Güvenli Anahtarlar (şifreleme) açık.
Bir dosyanın üzerine yazmak onu flash bellekten silmez. Şifreleyin, sonra anahtarı yok edin - bu gerçek bir silmedir:
function deleteNoteForReal() {
if (!window.AppMintKeystore || !window.WebToApkFS) return;
if (!confirm('Delete this note forever?')) return;
var gone = window.AppMintKeystore.deleteKey('vault'); // secret.bin is unreadable from now on
window.WebToApkFS.delete('secret.bin'); // tidy up the file too
alert(gone ? 'Deleted.' : 'Nothing to delete.');
}Ayarlarda "Her şeyi sil": bu uygulamanın oluşturduğu her anahtarı yok edin, sonra sayfanın depolama alanını temizleyin:
function eraseEverything() {
var K = window.AppMintKeystore;
if (!K || !K.isAvailable()) return;
if (!confirm('Erase all protected data on this phone? This cannot be undone.')) return;
var aliases = K.listKeys();
aliases.forEach(function (alias) { K.deleteKey(alias); });
localStorage.clear();
alert('Erased ' + aliases.length + ' key(s).');
location.reload();
}Çok fazla yanlış uygulama PIN'inden sonra kasayı kendini imha ettirin:
var MAX_TRIES = 5;
function onWrongPin() {
var tries = Number(localStorage.getItem('pinTries') || 0) + 1;
localStorage.setItem('pinTries', String(tries));
if (tries < MAX_TRIES) return alert((MAX_TRIES - tries) + ' tries left.');
if (window.AppMintKeystore) window.AppMintKeystore.deleteKey('vault'); // vault unreadable from now on
localStorage.removeItem('vaultData');
localStorage.removeItem('pinTries');
alert('Too many wrong PINs. The vault was erased.');
}Notlar: Geri alma ve kurtarma yoktur. isHardwareBacked(alias) sonucu false ise anahtar yazılımda duruyordu - kullanıcıya geri alınamaz bir silme vaat etmeden önce bunu söyleyin.
AppMintKeystore.encrypt yardımcı#
window.AppMintKeystore.encrypt(alias, base64)
Örnek
base64 veriyi güvenli bir anahtarla şifreler. Sonucu istediğiniz yerde saklayın - anahtar olmadan işe yaramaz.
Döndürür: hemen bir nesne (Promise değil): {ok:true, base64} (IV + şifreli metin + etiket) veya {ok:false, error, detail}. Gerekir: derleme sırasında Güvenli Anahtarlar (şifreleme) açık olmalı ve şuradan bir anahtar: AppMintKeystore.generateKey.
function toBase64(text) { return btoa(unescape(encodeURIComponent(text))); }
function saveSecret(text) {
if (!window.AppMintKeystore || !window.AppMintKeystore.isAvailable()) return false;
var r = window.AppMintKeystore.encrypt('vault', toBase64(text));
if (r.ok) {
localStorage.setItem('secret', r.base64);
return true;
}
if (r.error === 'auth-required') {
// the key needs a fresh unlock: ask for the fingerprint, then call saveSecret again
unlockThen(function () { saveSecret(text); });
} else {
alert('Could not encrypt: ' + r.error);
}
return false;
}unlockThen authenticateBiometricEx üzerinde oluşturulabilir (bu örneğe bakın).
Herhangi bir boyutta şifreli DOSYA yazmak için WebToApkFS.writeSealed(path, base64, alias) kullanın - aynı anahtarla parça parça şifreler.
Küçük bir JSON nesnesini (bir not, bir belirteç, ayarlar) mühürleyin ve localStorage'da tutun:
function sealJson(alias, obj) {
if (!window.AppMintKeystore || !window.AppMintKeystore.isAvailable()) return null;
var b64 = btoa(unescape(encodeURIComponent(JSON.stringify(obj))));
var r = window.AppMintKeystore.encrypt(alias, b64);
if (!r.ok) { console.warn('encrypt failed:', r.error, r.detail); return null; }
return r.base64;
}
var sealed = sealJson('notes', { title: 'Shopping', items: ['milk', 'eggs'] });
if (sealed) localStorage.setItem('note-1', sealed);Anahtarı ilk gerektiğinde oluşturun, sonra şifreleyin:
function encryptWithKeyReady(alias, b64) {
var ks = window.AppMintKeystore;
if (!ks || !ks.isAvailable()) return { ok: false, error: 'unsupported' };
var r = ks.encrypt(alias, b64);
if (!r.ok && r.error === 'no-such-key') {
var g = ks.generateKey(alias); // plain key, no unlock needed
if (!g.ok) return g;
r = ks.encrypt(alias, b64);
}
return r; // {ok:true, base64} or {ok:false, error, detail}
}Notlar: Çağrı başına en fazla 4 MB (chunk too large). Hatalar: no-such-key, auth-required, key-invalidated (ekran kilidi değişti - anahtar gitti), bad base64, disabled, foreign_origin, unsupported.
AppMintKeystore.generateKey yardımcı#
window.AppMintKeystore.generateKey(alias, options)
Örnek
Android Keystore'da bir AES-256-GCM anahtarı oluşturur (veya değiştirir). Anahtar güvenli donanımdan asla çıkmaz; sayfanız yalnızca adını kullanır.
Döndürür: hemen bir nesne (Promise değil): {ok:true, alias, hardwareBacked} veya {ok:false, error, detail}. Gerekli: derleme yaparken Güvenli Anahtarlar (şifreleme) açık (bkz. AppMintKeystore.isAvailable).
function createVault() {
if (!window.AppMintKeystore || !window.AppMintKeystore.isAvailable()) {
alert('Secure keys are not available in this app.');
return;
}
var r = window.AppMintKeystore.generateKey('vault', {
requireAuth: true, // usable only after a fingerprint / PIN unlock...
authValiditySeconds: 30 // ...for 30 seconds after it
});
if (!r.ok) { alert('Could not create the key: ' + r.error); return; }
console.log('Hardware key:', r.hardwareBacked);
}Kilit açma gerektirmeyen düz bir anahtar:
var r = window.AppMintKeystore.generateKey('notes'); // options default to {}Ayrı güvenli çipi (StrongBox) zorunlu kılın. Daha zayıf bir anahtar vermek yerine başarısız olur:
var r = window.AppMintKeystore.generateKey('wallet', { strongBox: true });
if (!r.ok && r.error === 'strongbox-unavailable') {
alert('This phone has no secure chip.');
}Notlar: Takma ad: harfler, rakamlar, _ - ., en fazla 64 karakter (aksi halde error:"bad alias"). Var olan bir takma adı kullanmak anahtarı değiştirir ve eski anahtarla mühürlenen veri kaybolur. Diğer hatalar: disabled, bad options json, foreign_origin, unsupported (köprü yok).
AppMintKeystore.hasKey yardımcı#
window.AppMintKeystore.hasKey(alias)
Örnek
Bu takma adla bir güvenli anahtarın var olup olmadığını söyler.
Döndürür: hemen true / false. Gerekli: derleme yaparken Güvenli Anahtarlar (şifreleme) açık.
function startVault() {
if (!window.AppMintKeystore || !window.AppMintKeystore.isAvailable()) return;
if (window.AppMintKeystore.hasKey('vault')) {
showUnlockScreen();
} else {
showCreateVaultScreen();
}
}
window.addEventListener('load', startVault);İlk kayıttan önce bir anahtarın var olduğundan emin olun, yalnızca bir kez oluşturun:
function ensureKey(alias) {
var ks = window.AppMintKeystore;
if (!ks || !ks.isAvailable()) return false;
if (ks.hasKey(alias)) return true;
var r = ks.generateKey(alias); // generateKey REPLACES an existing key, so only call it when hasKey says no
if (!r.ok) console.warn('Could not create key:', r.error);
return r.ok;
}
if (ensureKey('notes')) enableSaveButton();Anahtarı kaybolmuş (silinmiş ya da uygulama verisi onsuz geri yüklenmiş) mühürlü verileri temizleyin:
function checkVault() {
var ks = window.AppMintKeystore;
if (!ks || !ks.isAvailable()) return;
var sealed = localStorage.getItem('secret');
if (sealed && !ks.hasKey('vault')) {
localStorage.removeItem('secret'); // without the key it can never be opened
showMessage('Your saved secret could not be recovered and was removed.');
}
}
window.addEventListener('load', checkVault);Notlar: Güvenli Anahtarlar kapalıyken false yanıtını verir; bu yüzden "henüz anahtar yok" ile "özellik bu uygulamada yok" durumlarını ayırt etmeniz gerekiyorsa önce isAvailable() kontrol edin.
AppMintKeystore.isAvailable yardımcı#
window.AppMintKeystore.isAvailable()
Örnek
Bu uygulamada donanım destekli güvenli anahtarların kullanılıp kullanılamayacağını söyler.
Döndürür: true / false, hemen (Promise değil). Gerekir: derleme sırasında Güvenli Anahtarlar (şifreleme) açık olmalı. window.AppMintKeystore nesnesi, Güvenli Anahtarlar veya Yerel Klasör Erişimi (SAF) açık olduğunda (ilk betiğiniz çalışmadan önce) kurulur; isAvailable() Güvenli Anahtarlar için yanıt verir.
function secureKeysReady() {
return !!window.AppMintKeystore && window.AppMintKeystore.isAvailable();
}
// Check when the user acts (the helper is added when the page finishes loading):
document.getElementById('vault-button').addEventListener('click', function () {
if (!secureKeysReady()) {
alert('The secure vault is not available in this app.');
return;
}
openVault();
});Bu uygulamada özellik yoksa tüm güvenli kasa denetimlerini gizleyin:
window.addEventListener('load', function () {
var ok = !!window.AppMintKeystore && window.AppMintKeystore.isAvailable();
document.querySelectorAll('.needs-secure-keys').forEach(function (el) {
el.hidden = !ok;
});
});Hangi ekranı göstereceğinize karar verirken "özellik kapalı" ile "henüz anahtar yok" durumunu ayırt edin:
function vaultState() {
var ks = window.AppMintKeystore;
if (!ks || !ks.isAvailable()) return 'off'; // a browser, or Secure Keys not on in this build
return ks.hasKey('vault') ? 'ready' : 'new';
}
document.getElementById('vault-button').addEventListener('click', function () {
var state = vaultState();
if (state === 'off') alert('The secure vault is not available in this app.');
else if (state === 'new') showCreateVaultScreen();
else showUnlockScreen();
});Notlar: Yardımcı, sayfa yüklendikten sonra eklenir; bu yüzden sayfa hâlâ ayrıştırılırken çalışan bir betikte test etmeyin - bir tıklama işleyicisinde veya load sonrasında test edin. Tarayıcıda window.AppMintKeystore yoktur; yukarıdaki kontrol hata vermeden false döndürür.
AppMintKeystore.isHardwareBacked yardımcı#
window.AppMintKeystore.isHardwareBacked(alias)
Örnek
Bir anahtarın yazılımda değil, telefonun güvenli donanımında (TEE veya StrongBox) bulunup bulunmadığını söyler.
Döndürür: hemen true / false. Anahtar yoksa false. Gerekli: derleme yaparken Güvenli Anahtarlar (şifreleme) açık.
function showKeyStrength() {
if (!window.AppMintKeystore || !window.AppMintKeystore.hasKey('vault')) return;
var hw = window.AppMintKeystore.isHardwareBacked('vault');
document.getElementById('strength').textContent = hw
? 'Protected by secure hardware'
: 'Protected by software (this phone has no secure hardware for keys)';
}Yüksek değerli bir sırrı (cüzdan tohumu, kurtarma kodu) yalnızca anahtarı güvenli donanımdaysa saklayın:
function walletKeyIsHardware() {
var ks = window.AppMintKeystore;
if (!ks || !ks.isAvailable()) return false;
if (!ks.hasKey('wallet')) {
var r = ks.generateKey('wallet', { requireAuth: true });
if (!r.ok) return false;
}
return ks.isHardwareBacked('wallet');
}
if (!walletKeyIsHardware()) {
alert('This phone cannot keep the wallet key in secure hardware.');
}Bir destek raporu için her anahtarın nerede durduğunu listeleyin:
function keyReport() {
var ks = window.AppMintKeystore;
if (!ks || !ks.isAvailable()) return { secureKeys: false };
return {
secureKeys: true,
keys: ks.listKeys().map(function (alias) {
return { alias: alias, hardware: ks.isHardwareBacked(alias) };
})
};
}
console.log(JSON.stringify(keyReport()));Notlar: generateKey anahtarı oluşturduktan hemen sonra hardwareBacked de döndürür.
AppMintKeystore.listKeys yardımcı#
window.AppMintKeystore.listKeys()
Örnek
Sayfalarınızın oluşturduğu her güvenli anahtarın takma adlarını listeler.
Döndürür: hemen sıralanmış bir metin dizisi, örn. ['notes', 'vault']. Hiç yoksa veya özellik kapalıysa []. Gerekli: derleme yaparken Güvenli Anahtarlar (şifreleme) açık.
function renderKeyList() {
var list = document.getElementById('key-list');
list.innerHTML = '';
if (!window.AppMintKeystore) return;
window.AppMintKeystore.listKeys().forEach(function (alias) {
var li = document.createElement('li');
li.textContent = alias + (window.AppMintKeystore.isHardwareBacked(alias) ? ' (hardware)' : '');
list.appendChild(li);
});
}"Tüm verilerimi sil" işleminde her anahtarı yok edin; böylece onlarla mühürlenen her şey okunamaz hale gelir:
function eraseAllKeys() {
var ks = window.AppMintKeystore;
if (!ks || !ks.isAvailable()) return 0;
var removed = 0;
ks.listKeys().forEach(function (alias) {
if (ks.deleteKey(alias)) removed++;
});
localStorage.clear(); // the sealed copies can no longer be opened anyway
return removed;
}Oturum açan her kullanıcı için bir anahtar tutun ve oturumu kapatan kullanıcıların anahtarlarını kaldırın:
function pruneUserKeys(currentUserId) {
var ks = window.AppMintKeystore;
if (!ks || !ks.isAvailable()) return;
var keep = 'user-' + currentUserId; // aliases: letters, digits, _ - . only
ks.listKeys().forEach(function (alias) {
if (alias.indexOf('user-') === 0 && alias !== keep) ks.deleteKey(alias);
});
}Notlar: Yalnızca köprü üzerinden oluşturulan anahtarlar listelenir; uygulamanın kendi dahili anahtarları asla gösterilmez.
authenticateBiometric köprü#
window.WebToApk.authenticateBiometric(callbackId: String, title: String, subtitle: String)
WebToApk.isBiometricAvailable() -> "available" | "no_hardware" | "not_enrolled" | "unavailable" WebToApk.authenticateBiometric(id, title, subtitle) Sonuç, Google Sign-In köprüsünün kullandığı aynı __webToApkAuth geri çağırma tablosuna iletilir: window.__webToApkAuth = window.__webToApkAuth || {}; window.__webToApkAuth['unlock'] = function (json) { var r = JSON.parse(json); // {ok:true} | {ok:false,error:"..."} if (r.ok) showApp(); }; WebToApk.authenticateBiometric('unlock', 'Unlock', 'Use your fingerprint');
Tek başına değil, grubu olan Parmak izi / biyometri köprüsü altında açıklanmıştır.
Örnek
Başlık ve alt başlıkla sistem parmak izi istemini gösterir. authenticateBiometricEx işlevinin basit biçimi (PIN seçeneği, özel bir İptal etiketi veya "güçlü" biyometri için onu kullanın).
Döndürür: hiçbir şey. Yanıt sonra gelir: kabuk window.__webToApkAuth[callbackId](json) işlevini '{"ok":true}' veya '{"ok":false,"error":"<code>"}' ile çağırır, sonra o kaydı kaldırır. Gerekli: derleme yaparken Parmak İzi işaretli (olmadan: error:"permission_missing").
Önce geri çağrıyı kaydedin, sonra çağırın:
function unlockWithFingerprint() {
return new Promise(function (resolve) {
if (!window.WebToApk || typeof window.WebToApk.authenticateBiometric !== 'function') {
resolve({ ok: false, error: 'not_in_app' });
return;
}
var id = 'bio_' + Date.now();
window.__webToApkAuth = window.__webToApkAuth || {};
window.__webToApkAuth[id] = function (json) { resolve(JSON.parse(json)); };
window.WebToApk.authenticateBiometric(id, 'Unlock', 'Touch the fingerprint sensor');
});
}
document.getElementById('unlock').addEventListener('click', async function () {
var r = await unlockWithFingerprint();
if (r.ok) showMyApp();
else if (r.error === 'user_cancel') { /* the user closed it — do nothing */ }
else if (r.error === 'none_enrolled') alert('Please add a fingerprint in phone settings.');
else if (r.error === 'lockout') alert('Too many tries. Wait a little and try again.');
else alert('Could not unlock: ' + r.error);
});Riskli bir işlemi önce parmak iziyle onaylayın (boş başlık uygulamanın adını gösterir):
function confirmItsYou(subtitle) {
return new Promise(function (resolve) {
if (!window.WebToApk || typeof window.WebToApk.authenticateBiometric !== 'function') {
resolve({ ok: false, error: 'not_in_app' });
return;
}
var id = 'confirm_' + Date.now();
window.__webToApkAuth = window.__webToApkAuth || {};
window.__webToApkAuth[id] = function (json) { resolve(JSON.parse(json)); };
window.WebToApk.authenticateBiometric(id, '', subtitle);
});
}
document.getElementById('delete-account').addEventListener('click', async function () {
var r = await confirmItsYou('Confirm to delete your account');
if (r.ok) deleteMyAccount();
else if (r.error !== 'user_cancel') alert('Not confirmed: ' + r.error);
});Arka planda bir dakikadan fazla kaldıktan sonra geri geldiğinde uygulamayı yeniden kilitleyin:
var hiddenAt = 0;
document.addEventListener('visibilitychange', async function () {
if (document.visibilityState === 'hidden') {
hiddenAt = Date.now();
return;
}
if (!hiddenAt || Date.now() - hiddenAt < 60000) return;
hiddenAt = 0;
hideMyApp();
var r = await unlockWithFingerprint(); // from the first example
if (r.ok) showMyApp();
else showLockedScreen(); // with its own "Unlock" button
});Notlar: Boş bir başlık uygulamanın adını kullanır. Yanlış parmak istemi BİTİRMEZ - geri çağırma yalnızca başarı, iptal veya gerçek bir hatada tetiklenir. Hata kodları authenticateBiometricEx ile aynıdır. Bu, telefonun sahibinin orada olduğunu kanıtlar; bir sunucuya kim olduğunu kanıtlamaz.
authenticateBiometricEx köprü#
window.WebToApk.authenticateBiometricEx(callbackId: String, optionsJson: String)
Tam biçim. [optionsJson] şunları kabul eder: title, subtitle, description, negativeButtonText, allowDeviceCredential (PIN/desen/parola yedeği), strong (BIOMETRIC_STRONG zorunlu kılar - ödemeyle ilgili her şey için kullanın). Hatalar tek bir boolean değil, ayrı kodlardır. Herhangi bir istemden önce: no_hardware | none_enrolled | unavailable (durum denetimi çalıştırılamadı - bkz. isBiometricAvailable). Android 9+ sistem isteminden: user_cancel | no_hardware | hw_unavailable | none_enrolled | lockout | lockout_permanent | no_device_credential | timeout | no_space | unable_to_process | vendor_error ve Android'in sonradan ekleyeceği bir kod için kendi ileti metni (veya `error_<code>`). Derlemede Fingerprint izni yoksa permission_missing. Android 7-8'de (API 24-27, yalnızca parmak izi) hata, üreticinin yazdığı telefonun kendi ileti metnidir - sabit bir kod değil.
Örnek
Sistem parmak izi / yüz istemini tüm seçeneklerle gösterir: ikinci bir giriş yolu olarak PIN veya desen, özel bir İptal etiketi ve yalnızca "güçlü" biyometri.
Döndürür: hiçbir şey. Yanıt sonra gelir: kabuk window.__webToApkAuth[callbackId](json) işlevini '{"ok":true}' veya '{"ok":false,"error":"<code>"}' ile çağırır, sonra o kaydı kaldırır. Gerekli: derleme yaparken Parmak İzi işaretli (olmadan: error:"permission_missing").
Yeniden kullanabileceğiniz küçük bir Promise sarmalayıcısı:
function verifyUser(options) {
return new Promise(function (resolve) {
if (!window.WebToApk || typeof window.WebToApk.authenticateBiometricEx !== 'function') {
resolve({ ok: false, error: 'not_in_app' });
return;
}
var id = 'bio_' + Date.now() + '_' + Math.random().toString(36).slice(2);
window.__webToApkAuth = window.__webToApkAuth || {};
window.__webToApkAuth[id] = function (json) { resolve(JSON.parse(json)); };
window.WebToApk.authenticateBiometricEx(id, JSON.stringify(options));
});
}Uygulamanın kilidini açın - parmak izi, yüz veya telefonun PIN'i/deseni:
async function unlockApp() {
var r = await verifyUser({
title: 'Unlock',
subtitle: 'Use your fingerprint or PIN',
allowDeviceCredential: true // Android 11+: the system adds "Use PIN"
});
if (r.ok) showMyApp();
else if (r.error === 'lockout') alert('Too many tries. Wait a little and try again.');
}Bir ödemeyi onaylayın - yalnızca güçlü biyometri, kendi İptal etiketinizle:
async function confirmPayment() {
var r = await verifyUser({
title: 'Confirm payment',
description: 'Pay 12.00 to Coffee House',
negativeButtonText: 'Not now',
strong: true // BIOMETRIC_STRONG (Android 11+)
});
if (r.ok) sendPayment();
else if (r.error !== 'user_cancel') alert('Could not confirm: ' + r.error);
}requireAuth ile oluşturulmuş bir Keystore anahtarının kilidini açın, sonra yeniden deneyin:
async function openVault() {
var r = await verifyUser({ title: 'Open vault', allowDeviceCredential: true });
if (r.ok) readSecret(); // AppMintKeystore.decrypt works for authValiditySeconds now
}Notlar: Hata kodları: user_cancel, none_enrolled, no_hardware, hw_unavailable, lockout (bekleyip yeniden deneyin), lockout_permanent (kullanıcı telefonun kilidini önce PIN ile açmalı), no_device_credential, timeout, permission_missing, unavailable ve nadiren no_space, unable_to_process, vendor_error. Android 7-8'de kabuk kendi iletişim kutusunu gösterir ve hata sistemin ileti metnidir. allowDeviceCredential ve negativeButtonText birlikte kullanılmaz: PIN seçeneğiyle sistem kendi düğmesini çizer. Yanlış bir parmak istemi bitirmez.
decryptWithKey köprü#
window.WebToApk.decryptWithKey(alias: String, base64Payload: String): String
[encryptWithKey] işlemini tersine çevirir. Anahtar silindikten sonra `error:"no-such-key"` ile başarısız olur - yük bu durumda tasarım gereği kurtarılamaz. @return JSON `{ok, base64, error}`.
Örnek
Aynı Keystore anahtarıyla encryptWithKey tarafından oluşturulan veriyi çözer. Çoğu sayfa ayrıştırılmış nesneyi döndüren AppMintKeystore.decrypt(alias, base64) işlevini kullanır.
Döndürür: hemen bir JSON metni: {"ok":true,"base64":"<plain data>"} veya {"ok":false,"error":"...","detail":"..."}. Gerekli: derleme yaparken Güvenli Anahtarlar (şifreleme) açık.
function fromBase64(b64) { return decodeURIComponent(escape(atob(b64))); }
function openNote() {
if (!window.WebToApk || typeof window.WebToApk.decryptWithKey !== 'function') return null;
var sealed = localStorage.getItem('note');
if (!sealed) return null;
var r = JSON.parse(window.WebToApk.decryptWithKey('vault', sealed));
if (r.ok) return fromBase64(r.base64);
if (r.error === 'auth-required') {
askUserToUnlockThenRetry(); // unlock with authenticateBiometricEx, then call again
} else if (r.error === 'no-such-key' || r.error === 'key-invalidated') {
alert('This note can no longer be opened.'); // the key was deleted or the screen lock changed
} else {
alert('Could not open the note: ' + r.error);
}
return null;
}requireAuth:true ile oluşturulmuş bir anahtar için: auth-required olduğunda kilit açma istemini gösterin, sonra yeniden çözün:
function unlock() {
return new Promise(function (resolve) {
var id = 'unlock_' + Date.now();
window.__webToApkAuth = window.__webToApkAuth || {};
window.__webToApkAuth[id] = function (json) { resolve(JSON.parse(json)); };
window.WebToApk.authenticateBiometricEx(id, JSON.stringify({
title: 'Unlock your notes', strong: true, allowDeviceCredential: true
}));
});
}
async function openNoteWithUnlock() {
if (!window.WebToApk || typeof window.WebToApk.decryptWithKey !== 'function') return null;
var sealed = localStorage.getItem('note');
if (!sealed) return null;
var r = JSON.parse(window.WebToApk.decryptWithKey('vault', sealed));
if (!r.ok && r.error === 'auth-required') {
var auth = await unlock();
if (!auth.ok) return null; // cancelled or failed
r = JSON.parse(window.WebToApk.decryptWithKey('vault', sealed));
}
return r.ok ? decodeURIComponent(escape(atob(r.base64))) : null;
}Şifreli bir fotoğrafı gösterin: baytlara çözün, sonra bir blob URL ile görüntüleyin:
function showSealedPhoto(sealedB64, img) {
if (!window.WebToApk || typeof window.WebToApk.decryptWithKey !== 'function') return;
var r = JSON.parse(window.WebToApk.decryptWithKey('vault', sealedB64));
if (!r.ok) {
alert('Could not open the photo: ' + r.error);
return;
}
var bin = atob(r.base64);
var bytes = new Uint8Array(bin.length);
for (var i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
var url = URL.createObjectURL(new Blob([bytes], { type: 'image/jpeg' }));
img.onload = function () { URL.revokeObjectURL(url); };
img.src = url;
}Notlar: Anahtar silindikten sonra (deleteKey) veri bir daha çözülemez - tasarım gereği. Değiştirilmiş veya bozulmuş bir yük başarısız olur (GCM etiketi eşleşmez); bu durumda error yukarıdaki kodlardan biri değil, platformun iletisidir. Diğer kodlar: bad base64, disabled, foreign_origin.
deleteKey köprü#
window.WebToApk.deleteKey(alias: String): String
[alias] anahtarını kalıcı olarak yok eder. Onunla şifrelenen her şey, bu uygulama ve cihazı elinde tutan herkes dahil, çözülemez hale gelir.
Örnek
Bir Keystore anahtarını kalıcı olarak yok eder. Onunla şifrelenen her şey bir daha asla okunamaz - ne sizin, ne kullanıcının ne de telefonu elinde tutan herhangi birinin tarafından. Çoğu sayfa gerçek bir boolean döndüren AppMintKeystore.deleteKey(alias) işlevini kullanır.
Döndürür: "true" (silindi) veya "false" (böyle bir anahtar yok, Güvenli Anahtarlar kapalı veya uygulamanın kendi sayfası değil) DİZESİNİ, hemen. Gerekir: derleme sırasında Güvenli Anahtarlar (şifreleme) açık olmalı.
Bu, telefonda gerçek anlamda tek "güvenli silme"dir: bir dosyanın üzerine yazmak onu flash bellekten silmez, anahtarı yok etmek siler.
function destroyVault() {
if (!window.WebToApk || typeof window.WebToApk.deleteKey !== 'function') return;
if (!confirm('Delete the vault? This cannot be undone.')) return;
var gone = window.WebToApk.deleteKey('vault') === 'true';
localStorage.removeItem('note'); // the sealed data is now useless anyway
alert(gone ? 'Vault deleted.' : 'There was no vault to delete.');
}Bir anahtarı döndürün: veriyi eski anahtarla açın, yeni bir anahtarla mühürleyin, sonra eski anahtarı yok edin:
function rotateVault() {
var W = window.WebToApk;
if (!W || typeof W.deleteKey !== 'function') return false;
var sealed = localStorage.getItem('note');
if (!sealed) return false;
var clear = JSON.parse(W.decryptWithKey('vault', sealed));
if (!clear.ok) return false;
var made = JSON.parse(W.generateKey('vault2', '{}'));
if (!made.ok) return false;
var fresh = JSON.parse(W.encryptWithKey('vault2', clear.base64));
if (!fresh.ok) return false;
localStorage.setItem('note', fresh.base64);
localStorage.setItem('noteKey', 'vault2');
return W.deleteKey('vault') === 'true'; // the old copies are dead from here on
}Oturum kapatılırken "Bu telefonda beni unut": hesabın anahtarını yok edin, sonra önbelleğe alınmış verilerini silin:
function signOutAndForget(userId) {
var alias = 'user_' + userId;
if (window.WebToApk && typeof window.WebToApk.deleteKey === 'function') {
var gone = window.WebToApk.deleteKey(alias) === 'true';
console.log(gone ? 'Account key destroyed' : 'No key for this account');
}
localStorage.removeItem('messages_' + userId); // sealed with that key, unreadable now
signOut();
}Notlar: Kullanıcıya silmenin geri alınamaz olduğunu söylemeden önce isKeyHardwareBacked kontrol edin - yalnızca yazılımda duran bir anahtar daha zayıftır.
encryptWithKey köprü#
window.WebToApk.encryptWithKey(alias: String, base64Plaintext: String): String
[base64Plaintext] base64 verisini [alias] ile şifreler. Her çağrı kendi IV değerini üretir, bu yüzden büyük bir dosya parça parça şifrelenir - parçalar bağımsızdır ve herhangi bir sırayla çözülebilir. @return JSON `{ok, base64, error}`; `base64` değeri `IV || ciphertext || tag` biçimindedir.
Örnek
base64 veriyi bir Keystore anahtarıyla şifreler. Çoğu sayfa ayrıştırılmış nesneyi döndüren AppMintKeystore.encrypt(alias, base64) işlevini kullanır.
Döndürür: hemen bir JSON metni: {"ok":true,"base64":"<IV + ciphertext + tag>"} veya {"ok":false,"error":"...","detail":"..."}. Gerekli: derleme yaparken Güvenli Anahtarlar (şifreleme) açık ve şununla oluşturulmuş bir anahtar generateKey.
Girdi base64'tür. Metin için önce UTF-8 base64'e çevirin:
function toBase64(text) { return btoa(unescape(encodeURIComponent(text))); }
function sealNote(text) {
if (!window.WebToApk || typeof window.WebToApk.encryptWithKey !== 'function') return null;
var r = JSON.parse(window.WebToApk.encryptWithKey('vault', toBase64(text)));
if (r.ok) {
localStorage.setItem('note', r.base64); // safe to store anywhere: useless without the key
return r.base64;
}
if (r.error === 'auth-required') {
// key was made with requireAuth — unlock first (authenticateBiometricEx), then call again
askUserToUnlockThenRetry();
} else {
alert('Could not encrypt: ' + r.error);
}
return null;
}Saklamadan önce bir nesnenin tamamını (bir oturum, bazı ayarlar) JSON olarak mühürleyin:
function sealJson(alias, obj) {
if (!window.WebToApk || typeof window.WebToApk.encryptWithKey !== 'function') return null;
var b64 = btoa(unescape(encodeURIComponent(JSON.stringify(obj))));
var r = JSON.parse(window.WebToApk.encryptWithKey(alias, b64));
if (!r.ok) console.warn('encrypt failed: ' + r.error);
return r.ok ? r.base64 : null;
}
var sealed = sealJson('vault', { token: accessToken, savedAt: Date.now() });
if (sealed) localStorage.setItem('session', sealed);Kullanıcının seçtiği bir fotoğrafı şifreleyin (ikili veri, çağrı başına en fazla 4 MB):
document.getElementById('id-photo').addEventListener('change', async function (e) {
var file = e.target.files[0];
if (!file || !window.WebToApk || typeof window.WebToApk.encryptWithKey !== 'function') return;
var bytes = new Uint8Array(await file.arrayBuffer());
var bin = '';
for (var i = 0; i < bytes.length; i += 0x8000) {
bin += String.fromCharCode.apply(null, bytes.subarray(i, i + 0x8000));
}
var r = JSON.parse(window.WebToApk.encryptWithKey('vault', btoa(bin)));
if (r.ok) {
saveSealedPhoto(file.name, r.base64); // your own storage
} else if (r.error.indexOf('chunk too large') === 0) {
alert('That photo is too big. Pick one under 4 MB.');
} else {
alert('Could not encrypt the photo: ' + r.error);
}
});Notlar: Her çağrı yeni bir IV kullanır, bu yüzden aynı metin her seferinde farklı bir sonuç verir. Çağrı başına en fazla 4 MB (error:"chunk too large ..."); daha büyük dosyalar için parça parça şifreleyin veya WebToApkFS.writeSealed kullanın. Hata kodları: no-such-key, auth-required, key-invalidated (kullanıcı ekran kilidini değiştirdi - anahtar kalıcı olarak gitti), bad base64, disabled, foreign_origin.
generateKey köprü#
window.WebToApk.generateKey(alias: String, optionsJson: String): String
[alias] adında bir AES-256-GCM anahtarı oluşturur (veya değiştirir). @param optionsJson `{"requireAuth":bool, "authValiditySeconds":int, "strongBox":bool}`. `requireAuth` anahtarı cihaz kilidine bağlar; `strongBox`, güvenli öğesi olmayan cihazlarda istenenden zayıf bir anahtar vermek yerine tümüyle başarısız olur. @return JSON `{ok, alias, hardwareBacked, error}`.
Örnek
Android Keystore'da bir AES-256-GCM anahtarı oluşturur (veya değiştirir). Sayfa anahtarın kendisini değil, adını alır. Çoğu sayfa JSON işini sizin yerinize yapan AppMintKeystore.generateKey(alias, options) işlevini kullanır.
Döndürür: hemen bir JSON metni: {"ok":true,"alias":"vault","hardwareBacked":true} veya {"ok":false,"error":"...","detail":"..."}. Gerekli: derleme yaparken Güvenli Anahtarlar (şifreleme) açık.
function createVaultKey() {
if (!window.WebToApk || typeof window.WebToApk.generateKey !== 'function') {
alert('Secure keys work only in the app.');
return false;
}
var options = {
requireAuth: true, // key works only after the user unlocks (fingerprint / PIN)
authValiditySeconds: 30, // ...and for 30 seconds after that unlock
strongBox: false // true = demand the separate secure chip (fails if missing)
};
var r = JSON.parse(window.WebToApk.generateKey('vault', JSON.stringify(options)));
if (!r.ok) {
alert('Could not create the key: ' + r.error);
return false;
}
if (!r.hardwareBacked) console.log('Key is kept in software on this phone');
return true;
}Kilit açma kuralı olmayan düz bir anahtar (seçenekler şunlar olabilir: '{}'):
var r = JSON.parse(window.WebToApk.generateKey('notes', '{}'));Anahtarı ilk gerektiğinde bir kez oluşturun - generateKey işlevini yeniden çağırmak onu değiştirir ve zaten mühürlenmiş her şeyi sahipsiz bırakır:
function ensureKey(alias) {
if (!window.WebToApk || typeof window.WebToApk.generateKey !== 'function') return false;
if (window.WebToApk.hasKey(alias) === 'true') return true; // keep the existing key
var r = JSON.parse(window.WebToApk.generateKey(alias, '{}'));
if (!r.ok && r.error === 'disabled') {
console.warn('Secure Keys was not turned on for this build');
}
return r.ok;
}
if (ensureKey('notes')) enableEncryptedNotes();Bir cüzdan anahtarı için ayrı güvenli çipi zorunlu kılın ve telefonda yoksa kullanıcıya açıkça söyleyin:
function createWalletKey() {
if (!window.WebToApk || typeof window.WebToApk.generateKey !== 'function') return false;
var r = JSON.parse(window.WebToApk.generateKey('wallet', JSON.stringify({
requireAuth: true,
authValiditySeconds: 10,
strongBox: true
})));
if (r.ok) return true;
if (r.error === 'strongbox-unavailable') {
alert('The wallet needs a phone with a dedicated security chip.');
} else if (r.error === 'bad alias') {
alert('Key names may use letters, digits, _ - . only.');
} else {
alert('Could not create the wallet key: ' + r.error);
}
return false;
}Notlar: Takma ad yalnızca harf, rakam, _, -, . içerebilir ve en fazla 64 karakter olmalıdır; aksi halde error:"bad alias". Aynı takma adla yeniden çağırmak anahtarı DEĞİŞTİRİR ve eski anahtarla mühürlenmiş veri artık okunamaz. Hata kodları: disabled (Güvenli Anahtarlar açık değil), bad options json, strongbox-unavailable (strongBox:true istediniz ve telefonda güvenli çip yok ya da Android 9'dan eski), foreign_origin (uygulamanın kendi sayfası olmayan bir sayfadan çağrıldı).
hasKey köprü#
window.WebToApk.hasKey(alias: String): String
Bu uygulamanın keystore'unda [alias] adında bir anahtar varsa true.
Örnek
Bu takma adla bir Keystore anahtarının var olup olmadığını söyler. Çoğu sayfa gerçek bir boolean döndüren AppMintKeystore.hasKey(alias) kullanır.
Döndürür: hemen "true" veya "false" METNİ ("true" / "false"). Gerekli: derleme yaparken Güvenli Anahtarlar (şifreleme) açık (açık değilse yanıt her zaman "false").
function vaultExists() {
if (!window.WebToApk || typeof window.WebToApk.hasKey !== 'function') return false;
return window.WebToApk.hasKey('vault') === 'true'; // compare the string
}
if (!vaultExists()) {
showCreateVaultScreen();
}Başlangıç ekranını seçin: var olan bir kasanın kilidini açın ya da yeni kurun - ve anahtarı kaybolmuş mühürlü verileri temizleyin:
function chooseStartScreen() {
if (!window.WebToApk || typeof window.WebToApk.hasKey !== 'function') return showMyApp();
var hasVault = window.WebToApk.hasKey('vault') === 'true';
var hasData = localStorage.getItem('note') !== null;
if (hasVault) {
showUnlockScreen();
} else if (hasData) {
localStorage.removeItem('note'); // sealed with a key that no longer exists
showCreateVaultScreen('Your old vault could not be opened, so it was cleared.');
} else {
showCreateVaultScreen();
}
}Oturum açan her hesap için bir anahtar; o hesap bu telefonda ilk kez oturum açtığında oluşturulur:
function keyAliasFor(userId) {
// aliases allow letters, digits, _ - . and at most 64 characters
return 'user_' + String(userId).replace(/[^A-Za-z0-9_.-]/g, '_').slice(0, 59);
}
function onSignedIn(user) {
if (!window.WebToApk || typeof window.WebToApk.hasKey !== 'function') return openAccount(user, null);
var alias = keyAliasFor(user.id);
if (window.WebToApk.hasKey(alias) !== 'true') {
var r = JSON.parse(window.WebToApk.generateKey(alias, '{}'));
if (!r.ok) return alert('Could not set up secure storage: ' + r.error);
}
openAccount(user, alias);
}Notlar: Yanıt bir metindir, bu yüzden if (WebToApk.hasKey('vault')) her zaman doğrudur - === 'true' ile karşılaştırın. Yalnızca bu uygulamanın köprü üzerinden oluşturduğu anahtarları görürsünüz; kabuğun kendi anahtarları gizlidir.
isBiometricAvailable köprü#
window.WebToApk.isBiometricAvailable(): String
"available" | "no_hardware" | "not_enrolled" | "unavailable". Android 10+ yüz, iris ve parmak izini sayar; Android 6-9 yalnızca parmak izi sensörünü. "unavailable" = sensör geçici olarak kullanılamıyor veya kontrol çalıştırılamadı (örn. derleme Parmak İzi iznini etkinleştirmedi). Bkz. [BiometricStatus].
Örnek
Telefonun şu an biyometrik kilit açma (yüz, iris veya parmak izi) yapıp yapamayacağını söyler. Bir kilit açma düğmesi göstermeden önce kontrol edin.
Döndürür: hemen bir metin: "available", "no_hardware" (sensör yok), "not_enrolled" (sensör var ama kayıtlı bir şey yok veya ekran kilidi ayarlı değil) veya "unavailable" (sensör geçici olarak kullanılamıyor ya da kontrol çalıştırılamadı - örneğin derlemede Parmak İzi işaretlenmedi). Gerekli: derleme yaparken Parmak İzi işaretli - bu olmadan Android yanıt vermeyi reddeder ve sonuç şudur: "unavailable".
function setupFingerprintButton() {
var btn = document.getElementById('fingerprint-button');
if (!window.WebToApk || typeof window.WebToApk.isBiometricAvailable !== 'function') {
btn.hidden = true; // browser: no fingerprint bridge
return;
}
var state = window.WebToApk.isBiometricAvailable();
if (state === 'available') {
btn.hidden = false;
} else if (state === 'not_enrolled') {
btn.hidden = true;
showHint('Add a fingerprint in your phone settings to unlock with it.');
} else {
btn.hidden = true; // no_hardware / unavailable
}
}Çalışamadığında nedeniyle birlikte soluklaşan bir "Parmak iziyle kilidi aç" ayar anahtarı:
var BIO_REASONS = {
no_hardware: 'This phone has no fingerprint or face sensor.',
not_enrolled: 'Set up a fingerprint or face unlock in your phone settings first.',
unavailable: 'The sensor cannot be used right now.'
};
function renderBioSwitch() {
var sw = document.getElementById('bio-switch');
var note = document.getElementById('bio-note');
var inApp = window.WebToApk && typeof window.WebToApk.isBiometricAvailable === 'function';
var state = inApp ? window.WebToApk.isBiometricAvailable() : 'not_in_app';
sw.disabled = state !== 'available';
if (sw.disabled) sw.checked = false;
note.textContent = state === 'not_in_app' ? 'Available in the app.' : (BIO_REASONS[state] || '');
}Kullanıcı telefon ayarlarından geri döndüğünde, yeni bir parmak izi eklemiş olabileceği için tekrar kontrol edin:
document.addEventListener('visibilitychange', function () {
if (document.visibilityState !== 'visible') return;
if (!window.WebToApk || typeof window.WebToApk.isBiometricAvailable !== 'function') return;
if (window.WebToApk.isBiometricAvailable() === 'available') {
renderBioSwitch();
showHint('Fingerprint unlock is ready. Turn it on in Settings.');
}
});Notlar: Android 10 ve üstünde kontrol yüz, iris ve parmak izini sayar; yalnızca yüzle kilit açan bir telefon "available" yanıtı verir. Android 6-9'da yalnızca parmak izi sensörüne bakar; bu yüzden orada yalnızca yüzü olan telefon "no_hardware" yanıtı verir; authenticateBiometricEx içinde allowDeviceCredential:true ile kullanıcı yine telefonun PIN'i, deseni veya parolasıyla kilidi açabilir (Android 11+).
isKeyHardwareBacked köprü#
window.WebToApk.isKeyHardwareBacked(alias: String): String
[alias] yazılımda değil TEE'de veya güvenli bir öğede duruyorsa true. Bir kullanıcıya anahtarı yok etmenin geri alınamaz olduğunu vaat etmeden önce kontrol etmeye değer.
Örnek
Bir anahtarın yazılımda değil, telefonun güvenli donanımında (TEE veya StrongBox çipi) bulunup bulunmadığını söyler. Çoğu sayfa gerçek bir boolean döndüren AppMintKeystore.isHardwareBacked(alias) kullanır.
Döndürür: "true" veya "false" DİZESİNİ, hemen. Anahtar yoksa da "false". Gerekir: derleme sırasında Güvenli Anahtarlar (şifreleme) açık olmalı.
function describeVault() {
if (!window.WebToApk || typeof window.WebToApk.isKeyHardwareBacked !== 'function') return;
var hw = window.WebToApk.isKeyHardwareBacked('vault') === 'true';
document.getElementById('vault-info').textContent = hw
? 'Your key is locked in this phone\'s secure hardware.'
: 'Your key is protected by software on this phone.';
}Anahtarı yalnızca yazılımda tutabilen bir telefonda yüksek değerli bir sırrı saklamayı reddedin:
function setUpWalletKey() {
var W = window.WebToApk;
if (!W || typeof W.isKeyHardwareBacked !== 'function') return false;
var r = JSON.parse(W.generateKey('wallet', JSON.stringify({ requireAuth: true })));
if (!r.ok) return false;
if (W.isKeyHardwareBacked('wallet') !== 'true') {
W.deleteKey('wallet');
alert('This phone cannot keep the wallet key in secure hardware, so the wallet is off here.');
return false;
}
return true;
}İzin verilecekleri belirleyebilmesi için sunucunuza oturum açmayla birlikte küçük bir cihaz güvenliği özeti gönderin:
function deviceSecurity() {
var W = window.WebToApk;
var inApp = !!W && typeof W.isKeyHardwareBacked === 'function';
return {
secureKeys: inApp && W.isKeystoreEnabled() === 'true',
hardwareKey: inApp && W.isKeyHardwareBacked('vault') === 'true'
};
}
fetch('/api/sign-in', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: email, password: password, device: deviceSecurity() })
});Notlar: Arayüzünüzde "donanım" demeyin, yalnızca bu şu olduğunda: "true".
isKeystoreEnabled köprü#
window.WebToApk.isKeystoreEnabled(): String
Oluşturucunun bu uygulama için anahtar deposu köprüsünü etkinleştirip etkinleştirmediği.
Örnek
Oluşturucunun bu uygulama için Keystore köprüsünü açıp açmadığını söyler. Çoğu sayfa gerçek bir boolean döndüren AppMintKeystore.isAvailable() işlevini kullanır.
Döndürür: hemen "true" veya "false" METNİ ("true" / "false"). Gerekli: çağırmak için bir şey yok; yalnızca derleme yaparken Güvenli Anahtarlar (şifreleme) açıldıysa "true" yanıtı verir.
function keystoreReady() {
return !!window.WebToApk &&
typeof window.WebToApk.isKeystoreEnabled === 'function' &&
window.WebToApk.isKeystoreEnabled() === 'true';
}
document.getElementById('vault-button').hidden = !keystoreReady();"Beni hatırla" seçeneğini yalnızca belirteç şifreli saklanabiliyorsa sunun:
var canSeal = !!window.WebToApk &&
typeof window.WebToApk.isKeystoreEnabled === 'function' &&
window.WebToApk.isKeystoreEnabled() === 'true';
var remember = document.getElementById('remember-me');
remember.parentElement.hidden = !canSeal;
function afterSignIn(token) {
if (!canSeal || !remember.checked) return; // nothing stored in plain text
if (window.WebToApk.hasKey('session') !== 'true') window.WebToApk.generateKey('session', '{}');
var r = JSON.parse(window.WebToApk.encryptWithKey('session', btoa(token)));
if (r.ok) localStorage.setItem('token', r.base64);
}Test ederken "tarayıcıda açıldı" ile "uygulama Güvenli Anahtarlar olmadan derlendi" durumlarını ayırt edin:
function keystoreStatus() {
if (!window.WebToApk) return 'browser: no app bridge';
if (typeof window.WebToApk.isKeystoreEnabled !== 'function') return 'app without the keystore bridge';
return window.WebToApk.isKeystoreEnabled() === 'true'
? 'Secure Keys on'
: 'Secure Keys off in this build';
}
console.log('Keystore:', keystoreStatus());Notlar: Bu "false" olduğunda, diğer her anahtar yöntemi "false", "[]" veya {ok:false, error:"disabled"} yanıtı verir. Çalışamayacak bir düğme sunmak yerine özelliği gizleyin.
listKeys köprü#
window.WebToApk.listKeys(): String
Bu sayfanın oluşturduğu her anahtar takma adının JSON dizisi.
Örnek
Bu uygulamanın sayfalarının oluşturduğu her Keystore anahtarının takma adlarını listeler. Çoğu sayfa ayrıştırılmış diziyi döndüren AppMintKeystore.listKeys() işlevini kullanır.
Döndürür: ada göre sıralanmış bir JSON dizi dizesini hemen: '["notes","vault"]'. Gerekir: derleme sırasında Güvenli Anahtarlar (şifreleme) açık olmalı (açık değilse: "[]").
function showKeys() {
if (!window.WebToApk || typeof window.WebToApk.listKeys !== 'function') return;
var aliases = JSON.parse(window.WebToApk.listKeys());
document.getElementById('keys').textContent =
aliases.length ? aliases.join(', ') : 'No keys yet';
}Her anahtarı, nerede durduğunu ve bir Sil düğmesini listeleyen bir "Güvenlik anahtarları" ayar ekranı:
function renderKeyManager() {
if (!window.WebToApk || typeof window.WebToApk.listKeys !== 'function') return;
var list = document.getElementById('key-list');
list.innerHTML = '';
JSON.parse(window.WebToApk.listKeys()).forEach(function (alias) {
var hw = window.WebToApk.isKeyHardwareBacked(alias) === 'true';
var li = document.createElement('li');
li.textContent = alias + (hw ? ' (secure hardware) ' : ' (software) ');
var del = document.createElement('button');
del.textContent = 'Delete';
del.onclick = function () {
if (!confirm('Delete "' + alias + '"? Data sealed with it is lost for good.')) return;
window.WebToApk.deleteKey(alias);
renderKeyManager();
};
li.appendChild(del);
list.appendChild(li);
});
}Oturum kapatılırken, telefonda önbelleğe alınmış hiçbir şeyin bir daha okunamaması için hesap başına her anahtarı (adı user_...) yok edin:
function forgetAllAccounts() {
if (!window.WebToApk || typeof window.WebToApk.listKeys !== 'function') return 0;
var removed = 0;
JSON.parse(window.WebToApk.listKeys()).forEach(function (alias) {
if (alias.indexOf('user_') === 0 && window.WebToApk.deleteKey(alias) === 'true') removed++;
});
return removed;
}
document.getElementById('sign-out').addEventListener('click', function () {
var n = forgetAllAccounts();
console.log('Destroyed ' + n + ' account key(s)');
signOut();
});Notlar: Yalnızca köprü üzerinden oluşturulan anahtarlar listelenir; uygulamanın kendi iç anahtarları asla gösterilmez. Uygulamanın kendisine ait olmayan bir sayfadan (uygulamada yüklenen başka bir site) çağrıldığında da "[]" yanıtını verir.