Skip to content

Commit 5ee4913

Browse files
authored
fix: adjust auto lock features (#698)
1 parent 9cc0b74 commit 5ee4913

File tree

13 files changed

+138
-40
lines changed

13 files changed

+138
-40
lines changed

packages/adena-extension/src/App/use-app.ts

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useEffect } from 'react';
22
import { useLocation } from 'react-router-dom';
33

4+
import { ADENA_WALLET_EXTENSION_ID } from '@common/constants/storage.constant';
45
import { useAccountName } from '@hooks/use-account-name';
56
import { useWalletContext } from '@hooks/use-context';
67
import { useCurrentAccount } from '@hooks/use-current-account';
@@ -19,6 +20,12 @@ const useApp = (): void => {
1920
const { pathname, key } = useLocation();
2021
const { scrollMove } = useScrollHistory();
2122

23+
useEffect(() => {
24+
try {
25+
chrome?.runtime?.connect({ name: ADENA_WALLET_EXTENSION_ID });
26+
} catch {}
27+
}, []);
28+
2229
useEffect(() => {
2330
checkNetworkState();
2431
}, [pathname]);

packages/adena-extension/src/background.ts

+58-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { AlarmKey } from '@common/constants/alarm-key.constant';
1+
import { AlarmKey, SCHEDULE_ALARMS } from '@common/constants/alarm-key.constant';
2+
import { ADENA_WALLET_EXTENSION_ID } from '@common/constants/storage.constant';
23
import { MemoryProvider } from '@common/provider/memory/memory-provider';
34
import { ChromeLocalStorage } from '@common/storage';
45
import { CommandHandler } from '@inject/message/command-handler';
@@ -9,6 +10,8 @@ import { MessageHandler } from './inject/message';
910
const inMemoryProvider = new MemoryProvider();
1011
inMemoryProvider.init();
1112

13+
initAlarms();
14+
1215
function existsWallet(): Promise<boolean> {
1316
const storage = new ChromeLocalStorage();
1417
return storage
@@ -53,39 +56,57 @@ chrome.action.onClicked.addListener(async () => {
5356
});
5457

5558
chrome.runtime.onConnect.addListener(async (port) => {
59+
if (port.name !== ADENA_WALLET_EXTENSION_ID) {
60+
return;
61+
}
62+
5663
inMemoryProvider.addConnection();
57-
await chrome.alarms.clear(AlarmKey.EXPIRED_PASSWORD);
64+
inMemoryProvider.updateExpiredTimeBy(null);
5865

5966
port.onDisconnect.addListener(async () => {
6067
inMemoryProvider.removeConnection();
6168

62-
if (inMemoryProvider.isActive()) {
63-
await chrome.alarms.clear(AlarmKey.EXPIRED_PASSWORD);
64-
} else {
65-
await chrome.alarms.create(AlarmKey.EXPIRED_PASSWORD, {
66-
delayInMinutes: inMemoryProvider.getExpiredPasswordDurationMinutes(),
67-
});
69+
if (!inMemoryProvider.isActive()) {
70+
const expiredTime = new Date().getTime() + inMemoryProvider.getExpiredPasswordDurationTime();
71+
inMemoryProvider.updateExpiredTimeBy(expiredTime);
72+
73+
console.info('Password Expired time:', new Date(expiredTime));
6874
}
6975
});
7076
});
7177

7278
chrome.alarms.onAlarm.addListener(async (alarm) => {
73-
if (alarm.name === AlarmKey.EXPIRED_PASSWORD) {
74-
await chrome.alarms.clear(AlarmKey.EXPIRED_PASSWORD);
79+
try {
80+
const currentTime = new Date().getTime();
81+
chrome.storage.local.set({ SESSION: currentTime });
7582

76-
if (inMemoryProvider.isActive()) {
77-
return;
78-
}
83+
switch (alarm?.name) {
84+
case AlarmKey.EXPIRED_PASSWORD:
85+
if (!inMemoryProvider.isExpired(currentTime)) {
86+
return;
87+
}
88+
89+
await chrome.storage.session.clear();
90+
await clearInMemoryKey(inMemoryProvider);
7991

80-
await chrome.storage.session.clear();
81-
await clearInMemoryKey(inMemoryProvider);
92+
inMemoryProvider.updateExpiredTimeBy(null);
93+
console.info('Password Expired');
94+
95+
break;
96+
default:
97+
break;
98+
}
99+
} catch (error) {
100+
console.error(error);
82101
}
102+
103+
return true;
83104
});
84105

85106
chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
86107
// Check metadata when tab is updated
87108
if (changeInfo.status === 'complete') {
88-
chrome.tabs.sendMessage(tabId, CommandMessage.command('checkMetadata'));
109+
chrome.tabs.sendMessage(tabId, CommandMessage.command('checkMetadata')).catch(console.info);
89110
}
90111
});
91112

@@ -97,3 +118,24 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
97118

98119
return MessageHandler.createHandler(inMemoryProvider, message, sender, sendResponse);
99120
});
121+
122+
function initAlarms(): void {
123+
SCHEDULE_ALARMS.map(initAlarmWithDelay);
124+
}
125+
126+
function initAlarmWithDelay(alarm: { key: string; periodInMinutes: number; delay: number }): void {
127+
if (alarm.delay === 0) {
128+
chrome.alarms.create(alarm.key, {
129+
periodInMinutes: alarm.periodInMinutes,
130+
});
131+
return;
132+
}
133+
134+
setTimeout(
135+
() =>
136+
chrome.alarms.create(alarm.key, {
137+
periodInMinutes: alarm.periodInMinutes,
138+
}),
139+
alarm.delay,
140+
);
141+
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
11
export enum AlarmKey {
22
EXPIRED_PASSWORD = 'EXPIRED_PASSWORD',
3+
WAKE_ALARM = 'WAKE_ALARM',
4+
WAKE_ALARM_DELAY_20S = 'WAKE_ALARM_DELAY_20S',
5+
WAKE_ALARM_DELAY_40S = 'WAKE_ALARM_DELAY_40S',
36
}
7+
8+
export const SCHEDULE_ALARMS: { key: string; periodInMinutes: number; delay: number }[] = [
9+
{ key: AlarmKey.EXPIRED_PASSWORD, periodInMinutes: 1, delay: 0 },
10+
{ key: AlarmKey.WAKE_ALARM, periodInMinutes: 1, delay: 0 },
11+
{ key: AlarmKey.WAKE_ALARM_DELAY_20S, periodInMinutes: 1, delay: 20_000 },
12+
{ key: AlarmKey.WAKE_ALARM_DELAY_40S, periodInMinutes: 1, delay: 40_000 },
13+
];

packages/adena-extension/src/common/constants/storage.constant.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
export const ADENA_WALLET_ID = 'adena-wallet';
2+
export const ADENA_WALLET_EXTENSION_ID = 'adena-wallet-extension';
13
export const WALLET_EXPORT_TYPE_STORAGE_KEY = 'WALLET_EXPORT_TYPE' as const;
24
export const WALLET_EXPORT_ACCOUNT_ID = 'WALLET_EXPORT_ACCOUNT_ID' as const;
35
export const QUESTIONNAIRE_EXPIRATION_MIN = 30 * 24 * 60;

packages/adena-extension/src/common/provider/gno/gno-provider.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export class GnoProvider extends GnoJSONRPCProvider {
108108
sequence,
109109
};
110110
} catch (e) {
111-
console.error(e);
111+
console.info(e);
112112
}
113113
return {
114114
...defaultAccount,

packages/adena-extension/src/common/provider/memory/memory-provider.ts

+19-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export class MemoryProvider {
44
private memory: Map<string, any> = new Map();
55
private activeConnections = 0;
66
private expiredPasswordDuration = EXPIRED_PASSWORD_DURATION_MIN;
7+
private expiredTime: number | null = null;
78

89
public get = <T = any>(key: string): T | null => {
910
if (!this.memory.get(key)) {
@@ -33,11 +34,27 @@ export class MemoryProvider {
3334
return this.activeConnections > 0;
3435
}
3536

36-
public getExpiredPasswordDurationMinutes(): number {
37-
return this.expiredPasswordDuration;
37+
public getExpiredPasswordDurationTime(): number {
38+
return this.expiredPasswordDuration * 60 * 1000;
3839
}
3940

4041
public setExpiredPasswordDurationMinutes(duration: number): void {
4142
this.expiredPasswordDuration = duration;
4243
}
44+
45+
public isExpired(time: number): boolean {
46+
if (this.isActive()) {
47+
return false;
48+
}
49+
50+
if (!this.expiredTime) {
51+
return false;
52+
}
53+
54+
return this.expiredTime < time;
55+
}
56+
57+
public updateExpiredTimeBy(time: number | null): void {
58+
this.expiredTime = time;
59+
}
4360
}

packages/adena-extension/src/common/utils/crypto-utils.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const encryptPassword = async (
1616
password: string,
1717
): Promise<{ encryptedKey: string; encryptedPassword: string }> => {
1818
const result = await sendMessage(CommandMessage.command('encryptPassword', { password }));
19-
if (result.code !== 200) {
19+
if (!result || result.code !== 200) {
2020
throw new Error('Encryption key not initialized.');
2121
}
2222

@@ -34,7 +34,7 @@ export const decryptPassword = async (iv: string, encryptedPassword: string): Pr
3434
encryptedPassword,
3535
}),
3636
);
37-
if (result?.code !== 200 || !result?.data?.password) {
37+
if (!result || result?.code !== 200 || !result?.data?.password) {
3838
throw new Error('Encryption key not initialized.');
3939
}
4040

@@ -45,8 +45,11 @@ export const clearInMemoryKey = async (): Promise<void> => {
4545
await sendMessage(CommandMessage.command('clearEncryptKey'));
4646
};
4747

48-
function sendMessage<T = any>(message: CommandMessageData): Promise<CommandMessageData<T>> {
49-
return new Promise((resolve) => {
48+
function sendMessage<T = any>(message: CommandMessageData): Promise<CommandMessageData<T> | null> {
49+
return new Promise<CommandMessageData<T> | null>((resolve) => {
5050
chrome.runtime.sendMessage(message, resolve);
51+
}).catch((error) => {
52+
console.warn(error);
53+
return null;
5154
});
5255
}

packages/adena-extension/src/components/pages/router/side-menu-layout/side-menu-container.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,13 @@ const SideMenuContainer: React.FC<SideMenuContainerProps> = ({ open, setOpen })
9797
setOpen(false);
9898
await walletService.lockWallet();
9999
await clearWallet();
100-
await chrome.runtime.sendMessage(CommandMessage.command('clearPopup'));
100+
101+
try {
102+
await chrome.runtime.sendMessage(CommandMessage.command('clearPopup'));
103+
} catch (error) {
104+
console.warn(error);
105+
}
106+
101107
await loadAccounts();
102108
navigate(RoutePath.Login, { replace: true });
103109
}, [walletService, navigate]);

packages/adena-extension/src/content.ts

+15-12
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,6 @@ import { EventMessageData } from '@inject/message';
33
import { CommandHandler } from '@inject/message/command-handler';
44
import { CommandMessageData } from '@inject/message/command-message';
55

6-
const sendMessage = (event: MessageEvent): void => {
7-
const message = event.data;
8-
chrome.runtime.sendMessage(message, (response) => {
9-
Promise.resolve(response).then((result) => {
10-
event.source?.postMessage(result, {
11-
targetOrigin: event.origin,
12-
});
13-
});
14-
return true;
15-
});
16-
};
17-
186
const loadScript = (): void => {
197
const container = document.head || document.documentElement;
208
const scriptElement = document.createElement('script');
@@ -62,6 +50,21 @@ const initExtensionListener = (): void => {
6250
});
6351
};
6452

53+
const sendMessage = (event: MessageEvent): void => {
54+
const message = event.data;
55+
56+
chrome.runtime.sendMessage(message, (response) => {
57+
Promise.resolve(response)
58+
.then((result) => {
59+
event.source?.postMessage(result, {
60+
targetOrigin: event.origin,
61+
});
62+
})
63+
.catch(console.info);
64+
return true;
65+
});
66+
};
67+
6568
loadScript();
6669
initListener();
6770
initExtensionListener();

packages/adena-extension/src/hooks/use-event.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const useEvent = (): UseEventReturn => {
1212
return;
1313
}
1414
const tabId = currentTab.id;
15-
chrome.tabs.sendMessage(tabId, message);
15+
chrome.tabs.sendMessage(tabId, message).catch(console.warn);
1616
});
1717
}
1818

packages/adena-extension/src/inject/executor/executor.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,11 @@ export class AdenaExecutor {
170170
key: this.eventKey,
171171
};
172172

173-
window.postMessage(this.eventMessage, window.location.origin);
173+
try {
174+
window.postMessage(this.eventMessage, window.location.origin);
175+
} catch (error) {
176+
console.warn(error);
177+
}
174178
this.messages[this.eventKey] = {
175179
request: this.eventMessage,
176180
response: undefined,

packages/adena-extension/src/inject/message/command-handler.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class CommandHandler {
7171
return;
7272
}
7373
} catch (error) {
74-
console.error(error);
74+
console.info(error);
7575
sendResponse(makeInternalErrorResponse(message));
7676
}
7777

packages/adena-extension/src/inject/message/commands/encrypt.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const KEY_LENGTH = 256; // AES-256 key length
66
const IV_LENGTH = 12; // GCM nonce length (12 bytes is recommended)
77

88
export async function getInMemoryKey(memoryProvider: MemoryProvider): Promise<CryptoKey | null> {
9-
const key = memoryProvider.get(MEMORY_KEY) || null;
9+
const key = memoryProvider?.get(MEMORY_KEY) || null;
1010
if (!key) {
1111
const generated = await generateInMemoryKey();
1212
memoryProvider.set(MEMORY_KEY, generated);
@@ -49,6 +49,10 @@ export const decryptPassword = async (
4949
iv: string,
5050
encryptedPassword: string,
5151
): Promise<string> => {
52+
if (!key || !iv || !encryptedPassword) {
53+
return '';
54+
}
55+
5256
const encryptedData = Buffer.from(encryptedPassword, 'base64');
5357
const ivBytes = Buffer.from(iv, 'base64');
5458
const dec = new TextDecoder();

0 commit comments

Comments
 (0)