-
Notifications
You must be signed in to change notification settings - Fork 0
/
content_script.ts
126 lines (109 loc) · 3.34 KB
/
content_script.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import { logger } from "src/logger";
import { alertWrapper } from "src/providers/alert";
import { getCurrentURL } from "src/providers/href";
import { sendMessage } from "src/providers/runtime";
import { loadStorageValues, saveStorageValues } from "src/providers/storage";
import { ClueConfig, HuntConfig } from "src/types/hunt_config";
import { SomeProgress } from "src/types/progress";
import { Decrypt } from "src/utils/encrypt";
import { nonNull } from "src/utils/helpers";
/**
* When a page is loaded:
* 1. Check if the stored hunt config is valid
* 2. Check if the current URL applies to any clues
* 3. If it does, send a message to the background/worker to render an update for the clue
*
* Notes:
* 1. Content Script is in charge of rendering an alert if desired
* 2. Content Script is in charge of updating progress and maxProgress* on opened
* 3. Worker is in charge of updating the badge text
*/
const CLUE_FOUND_TEXT =
"You found a clue! Click on the Scavenger Hunt icon to view the message.";
/* Parse hunt config and current page */
const checkHuntForURLMatch = (
huntConfig: HuntConfig,
maxProgress: number,
): ClueConfig | undefined => {
const {
encrypted,
clues,
options: { inOrder, silent },
} = huntConfig;
logger.info(`checking for match among ${clues.length} clues`);
for (let i = 0; i < clues.length; i++) {
const clue = clues[i];
// We could check for url earlier, but this is useful for testing fidelity without much cost.
const currentUrl = getCurrentURL();
const clueUrl = Decrypt(clue.url, encrypted, huntConfig.name);
const reg = new RegExp(clueUrl);
logger.info(`checking ${currentUrl} against ${clueUrl}`);
if (!currentUrl.match(reg) && !currentUrl.includes(clueUrl)) {
continue;
}
// If require in order and not in order, skip
if (inOrder && clue.id > maxProgress + 1) {
continue;
}
// Successfully found the matching URL. Now propagate the decrypted clue to the worker
if (!silent) {
alertWrapper(CLUE_FOUND_TEXT);
}
logger.info("found a match!");
return clue;
}
return undefined;
};
/* Send messages to worker */
const sendClueFound = (maxProgress: number, solvedClue: ClueConfig) => {
const currentProgress = solvedClue.id;
const sendClueFoundMessage = () => {
sendMessage({
status: "Found",
});
};
saveStorageValues(
{
maxProgress:
currentProgress > maxProgress ? currentProgress : maxProgress,
currentProgress,
},
sendClueFoundMessage,
);
};
const sendClueNotFound = () => {
sendMessage({
status: "Not Found",
});
};
const sendEmptyOrInvalidHunt = () => {
sendMessage({
status: "Invalid",
});
};
/* Handle storage and page */
const loadHuntCallback = (items: SomeProgress) => {
logger.info(items);
try {
if (items.huntConfig && nonNull(items.maxProgress)) {
const urlMatchClue = checkHuntForURLMatch(
items.huntConfig,
items.maxProgress ?? 0,
);
if (urlMatchClue) {
sendClueFound(items.maxProgress!, urlMatchClue);
} else {
sendClueNotFound();
}
} else {
sendEmptyOrInvalidHunt();
}
} catch (err) {
logger.warn(err);
sendEmptyOrInvalidHunt();
}
};
export const loadHuntProgress = () => {
loadStorageValues(["huntConfig", "maxProgress"], loadHuntCallback);
};
loadHuntProgress();