Release 1.1.1: remove gcm permission and dead token flow

This commit is contained in:
Dwindi Ramadhana
2026-02-20 21:07:51 +07:00
parent 5a67be8f70
commit 6f73977c2c
4 changed files with 3 additions and 129 deletions

View File

@@ -1,95 +1,11 @@
// Let Chrome open the panel when the toolbar icon is clicked // Let Chrome open the panel when the toolbar icon is clicked
// Guard: some Chromium variants may not expose sidePanel // Guard: some Chromium variants may not expose sidePanel
const hasSidePanel = !!chrome.sidePanel?.setOptions; const hasSidePanel = !!chrome.sidePanel?.setOptions;
const GCM_PROJECT_NUMBER = '1088502361802';
const EXT_TOKEN_KEY = 'dewemojiExtToken';
const GCM_LOCK_KEY = 'dewemojiExtTokenLockTs';
const GCM_LAST_ERR_KEY = 'dewemojiExtTokenLastError';
const GCM_LAST_ERR_TS_KEY = 'dewemojiExtTokenLastErrorTs';
const GCM_LOCK_WINDOW_MS = 60000;
let gcmRegisterPromise = null;
let gcmInMemoryLockTs = 0;
async function storeExtensionToken(token) {
try { await chrome.storage.local.set({ [EXT_TOKEN_KEY]: token }); } catch {}
}
async function getStoredToken() {
try {
const got = await chrome.storage.local.get([EXT_TOKEN_KEY]);
return got[EXT_TOKEN_KEY] || null;
} catch {
return null;
}
}
function registerGcmToken() {
if (gcmRegisterPromise) return gcmRegisterPromise;
if (!chrome?.gcm?.register) return Promise.resolve(null);
gcmRegisterPromise = new Promise((resolve) => {
(async () => {
if (gcmInMemoryLockTs && Date.now() - gcmInMemoryLockTs < GCM_LOCK_WINDOW_MS) {
return resolve(null);
}
// Avoid repeated register attempts within a short window
const lock = await chrome.storage.local.get([GCM_LOCK_KEY]);
const lastTs = Number(lock[GCM_LOCK_KEY] || 0);
if (Date.now() - lastTs < GCM_LOCK_WINDOW_MS) {
return resolve(null);
}
const now = Date.now();
gcmInMemoryLockTs = now;
await chrome.storage.local.set({ [GCM_LOCK_KEY]: now });
})().then(() => {
chrome.gcm.register([GCM_PROJECT_NUMBER], async (registrationId) => {
if (chrome.runtime.lastError || !registrationId) {
const msg = chrome.runtime.lastError?.message || 'no registrationId';
try { await chrome.storage.local.set({ [GCM_LAST_ERR_KEY]: msg, [GCM_LAST_ERR_TS_KEY]: Date.now() }); } catch {}
if (!/asynchronous operation is pending/i.test(msg)) {
console.warn('GCM register failed', msg);
}
// back off on pending errors
if (/asynchronous operation is pending/i.test(msg)) {
const now = Date.now();
gcmInMemoryLockTs = now;
try { await chrome.storage.local.set({ [GCM_LOCK_KEY]: now }); } catch {}
}
return resolve(null);
}
try { await chrome.storage.local.remove([GCM_LAST_ERR_KEY, GCM_LAST_ERR_TS_KEY]); } catch {}
await storeExtensionToken(registrationId);
console.log('GCM token stored', registrationId.slice(0, 8) + '…');
resolve(registrationId);
});
}).catch(() => resolve(null));
}).finally(() => {
gcmRegisterPromise = null;
});
return gcmRegisterPromise;
}
chrome.runtime.onInstalled.addListener(() => { chrome.runtime.onInstalled.addListener(() => {
if (hasSidePanel) chrome.sidePanel.setPanelBehavior?.({ openPanelOnActionClick: true }); if (hasSidePanel) chrome.sidePanel.setPanelBehavior?.({ openPanelOnActionClick: true });
}); });
// Intentionally do NOT auto-register on startup to avoid concurrent GCM calls.
chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
if (msg?.type !== 'dewemoji_get_ext_token') return;
(async () => {
const force = !!msg.force;
let token = await getStoredToken();
if (!token || force) {
await registerGcmToken();
// best-effort wait for storage to be populated
await new Promise(r => setTimeout(r, 300));
token = await getStoredToken();
}
sendResponse({ ok: !!token, token });
})();
return true;
});
// If you still want to ensure the correct path on click, setOptions ONLY: // If you still want to ensure the correct path on click, setOptions ONLY:
chrome.action.onClicked.addListener(async () => { chrome.action.onClicked.addListener(async () => {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });

View File

@@ -1,14 +1,13 @@
{ {
"name": "Dewemoji - Emojis Made Effortless", "name": "Dewemoji - Emojis Made Effortless",
"description": "Find and copy emojis instantly. Connect your account to use private keywords across web and extension.", "description": "Find and copy emojis instantly. Connect your account to use private keywords across web and extension.",
"version": "1.1.0", "version": "1.1.1",
"offline_enabled": false, "offline_enabled": false,
"permissions": [ "permissions": [
"storage", "storage",
"scripting", "scripting",
"activeTab", "activeTab",
"sidePanel", "sidePanel"
"gcm"
], ],
"host_permissions": [ "host_permissions": [
"<all_urls>", "<all_urls>",

View File

@@ -136,6 +136,6 @@
</div> </div>
<div id="toast" class="toast" role="status" aria-live="polite"></div> <div id="toast" class="toast" role="status" aria-live="polite"></div>
<script src="panel.js?ver=1.1.0"></script> <script src="panel.js?ver=1.1.1"></script>
</body> </body>
</html> </html>

View File

@@ -160,47 +160,6 @@ function categoryComparator(a, b) {
return a.localeCompare(b, undefined, { sensitivity: "base" }); // both not preferred → AZ return a.localeCompare(b, undefined, { sensitivity: "base" }); // both not preferred → AZ
} }
// === Extension verification token (GCM registration) ===
const EXT_TOKEN_KEY = 'dewemojiExtToken';
const EXT_TOKEN_COOLDOWN_MS = 60000;
let extTokenPromise = null;
let extTokenLastAttempt = 0;
async function getExtensionToken(force=false) {
if (extTokenPromise) return extTokenPromise;
extTokenPromise = (async () => {
try {
const got = await chrome.storage.local.get([EXT_TOKEN_KEY]);
if (got[EXT_TOKEN_KEY] && !force) return got[EXT_TOKEN_KEY];
if (!force && extTokenLastAttempt && Date.now() - extTokenLastAttempt < EXT_TOKEN_COOLDOWN_MS) {
return null;
}
extTokenLastAttempt = Date.now();
const res = await chrome.runtime.sendMessage({ type: 'dewemoji_get_ext_token', force });
if (res?.token) {
await chrome.storage.local.set({ [EXT_TOKEN_KEY]: res.token });
return res.token;
}
return null;
} catch (err) {
console.error('Token retrieval failed:', err);
return null;
}
})().finally(() => {
extTokenPromise = null;
});
return extTokenPromise;
}
async function getExtensionTokenCached() {
try {
const got = await chrome.storage.local.get([EXT_TOKEN_KEY]);
return got[EXT_TOKEN_KEY] || null;
} catch {
return null;
}
}
async function loadCategories() { async function loadCategories() {
// Try live endpoint; fall back silently to local list (no subs) // Try live endpoint; fall back silently to local list (no subs)
let ok = false; let ok = false;