Repository navigation
Expand file tree
/
Copy pathwelcome.html
More file actions
293 lines (276 loc) · 12.6 KB
/
Copy pathwelcome.html
File metadata and controls
293 lines (276 loc) · 12.6 KB
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
<!DOCTYPE html>
<!-- ══════════════════════════════════════════════════════════════════
welcome.html -- shown once, the first time this browser starts with the
FreeProxy VPN extension in it.
WHY THIS PAGE EXISTS
The extension is installed by the desktop app's installer, through
Windows policy. That means it appears in the browser without the user
ever visiting a store page or clicking Add -- so unless something says
so, the honest situation is that software they installed put an
extension in their browser silently. This page is that something. It is
the same thing IDM does when its integration module lands.
WHAT IT MAY AND MAY NOT SAY
Every claim on this page is checked against the app before it is shown:
the status row is fed by the live WebSocket state in background.js, not
by an assumption that the app is running. If the app is not running the
page says the extension is inert, because it is -- see the note in
background.js about the "only works while the app is running" rule.
══════════════════════════════════════════════════════════════════ -->
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FreeProxy VPN -- extension installed</title>
<style>
/* Same palette as popup.html, so this reads as one product. System font
stack only: a web font here would be a third-party request on a page
whose entire subject is not leaking anything. */
:root {
--ink: #e8eaf2;
--ink-dim: #9aa3bd;
--bg: #0b0d17;
--surface: #151827;
--surface-2: #1c2032;
--line: rgba(255,255,255,.07);
--purple: #5031b2;
--violet: #7c3aed;
--green: #22c55e;
--amber: #f59e0b;
--red: #ef4444;
}
* { box-sizing: border-box; }
html, body { margin: 0; min-height: 100%; }
body {
background:
radial-gradient(900px 520px at 15% -10%, rgba(124,58,237,.20), transparent 60%),
radial-gradient(700px 460px at 100% 0%, rgba(162,21,102,.16), transparent 55%),
var(--bg);
color: var(--ink);
font-family: 'Segoe UI Variable Text', 'Segoe UI', system-ui, -apple-system, sans-serif;
font-size: 14.5px;
line-height: 1.55;
-webkit-font-smoothing: antialiased;
display: flex; justify-content: center;
padding: 44px 20px 60px;
}
.wrap { width: 100%; max-width: 720px; }
/* ── hero ───────────────────────────────────────────────────── */
.hero {
display: flex; align-items: center; gap: 15px;
padding: 18px 20px;
border-radius: 16px 16px 0 0;
background: linear-gradient(145deg, #6b21a8 0%, #a21566 100%);
position: relative; overflow: hidden;
}
.hero::after {
content: ''; position: absolute; top: -60%; left: -30%;
width: 40%; height: 220%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,.16), transparent);
transform: rotate(18deg);
animation: sheen 6s ease-in-out infinite;
}
@keyframes sheen {
0%, 65% { transform: translateX(0) rotate(18deg); opacity: 0; }
70% { opacity: 1; }
100% { transform: translateX(700%) rotate(18deg); opacity: 0; }
}
.hero img { width: 46px; height: 46px; border-radius: 11px; flex: none;
filter: drop-shadow(0 3px 8px rgba(0,0,0,.4)); }
.hero h1 { margin: 0; font-size: 19px; font-weight: 600; letter-spacing: .2px; }
.hero p { margin: 2px 0 0; font-size: 12.5px; color: rgba(255,255,255,.78); }
.badge-new {
margin-left: auto; flex: none;
font-size: 10.5px; font-weight: 700; letter-spacing: .8px;
padding: 4px 9px; border-radius: 999px;
background: rgba(255,255,255,.16);
border: 1px solid rgba(255,255,255,.28);
}
/* ── card shell ─────────────────────────────────────────────── */
.card {
background: var(--surface);
border: 1px solid var(--line);
border-top: none;
padding: 20px;
}
.card:last-of-type { border-radius: 0 0 16px 16px; }
h2 { margin: 0 0 10px; font-size: 14px; font-weight: 600; letter-spacing: .3px;
color: var(--ink); text-transform: uppercase; }
p { margin: 0 0 10px; color: var(--ink-dim); }
p:last-child { margin-bottom: 0; }
b, strong { color: var(--ink); font-weight: 600; }
/* ── live status row ────────────────────────────────────────── */
.status {
display: flex; align-items: center; gap: 11px;
background: var(--surface-2);
border: 1px solid var(--line);
border-radius: 12px;
padding: 13px 15px;
}
.dot { width: 10px; height: 10px; border-radius: 50%; flex: none; background: #64748b; }
.dot.on { background: var(--green); animation: pulse-green 1.6s infinite; }
.dot.mid { background: var(--amber); animation: pulse-amber 1s infinite; }
.dot.off { background: var(--red); }
@keyframes pulse-green {
0% { box-shadow: 0 0 0 0 rgba(34,197,94,.55); }
70% { box-shadow: 0 0 0 8px rgba(34,197,94,0); }
100% { box-shadow: 0 0 0 0 rgba(34,197,94,0); }
}
@keyframes pulse-amber {
0% { box-shadow: 0 0 0 0 rgba(245,158,11,.55); }
70% { box-shadow: 0 0 0 8px rgba(245,158,11,0); }
100% { box-shadow: 0 0 0 0 rgba(245,158,11,0); }
}
.status .txt { flex: 1; min-width: 0; }
.status .txt b { display: block; font-size: 13.5px; }
.status .txt span { display: block; font-size: 12px; color: var(--ink-dim); }
/* ── numbered steps ─────────────────────────────────────────── */
ol.steps { margin: 0; padding: 0; list-style: none; counter-reset: s; }
ol.steps li {
counter-increment: s;
position: relative;
padding: 0 0 14px 40px;
color: var(--ink-dim);
}
ol.steps li:last-child { padding-bottom: 0; }
ol.steps li::before {
content: counter(s);
position: absolute; left: 0; top: 0;
width: 26px; height: 26px; border-radius: 50%;
display: grid; place-items: center;
font-size: 12.5px; font-weight: 700; color: #fff;
background: linear-gradient(145deg, var(--violet), var(--purple));
box-shadow: 0 2px 8px rgba(124,58,237,.35);
}
/* `> b:first-child`, not `b`: step 2 also bolds the extension's name mid
sentence, and a bare `li b` made that a block too, which stranded the
full stop after it on a line of its own. */
ol.steps li > b:first-child { display: block; margin-bottom: 1px; }
/* ── the "where is the icon" pointer ────────────────────────── */
.toolbar-hint {
display: flex; align-items: center; gap: 9px;
margin-top: 12px; padding: 10px 13px;
background: rgba(124,58,237,.10);
border: 1px dashed rgba(124,58,237,.45);
border-radius: 10px;
font-size: 12.5px; color: var(--ink-dim);
}
.toolbar-hint img { width: 20px; height: 20px; border-radius: 5px; flex: none; }
.toolbar-hint .arrow { font-size: 15px; color: var(--violet); animation: nudge 1.4s ease-in-out infinite; }
@keyframes nudge {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-3px); }
}
/* ── facts list ─────────────────────────────────────────────── */
ul.facts { margin: 0; padding-left: 20px; color: var(--ink-dim); }
ul.facts li { margin-bottom: 7px; }
ul.facts li:last-child { margin-bottom: 0; }
/* ── footer ─────────────────────────────────────────────────── */
.foot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
button {
font: inherit; font-size: 13.5px; font-weight: 600;
color: #fff; cursor: pointer;
padding: 10px 20px; border-radius: 10px;
border: 1px solid rgba(255,255,255,.10);
background: linear-gradient(145deg, var(--violet), var(--purple));
transition: transform .12s ease, box-shadow .12s ease;
}
button:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(124,58,237,.35); }
button:active { transform: translateY(0); }
button.ghost {
background: var(--surface-2);
color: var(--ink-dim);
border-color: var(--line);
}
button.ghost:hover { color: var(--ink); box-shadow: none; }
.foot .spacer { flex: 1; }
.tiny { font-size: 11.5px; color: var(--ink-dim); }
.note { margin-top: 12px; }
code {
font-family: 'Cascadia Mono', Consolas, monospace;
font-size: 12px;
background: var(--surface-2);
border: 1px solid var(--line);
border-radius: 5px; padding: 1px 5px;
}
</style>
</head>
<body>
<div class="wrap">
<div class="hero">
<img src="icon.png" alt="">
<div>
<h1>The FreeProxy VPN extension is now in this browser</h1>
<p>It was installed by the FreeProxy VPN desktop app -- nothing else added it.</p>
</div>
<div class="badge-new">NEW</div>
</div>
<!-- The live row. Everything in it comes from the app over the WebSocket;
welcome.js leaves it on "checking" until an answer actually arrives
rather than guessing at a state. -->
<div class="card">
<div class="status">
<div class="dot" id="dot"></div>
<div class="txt">
<b id="st-main">Checking the desktop app...</b>
<span id="st-sub">Asking the app what it is doing right now.</span>
</div>
</div>
</div>
<div class="card">
<h2>What it does</h2>
<ul class="facts">
<li>Sends this browser's traffic through the Tor engine inside the desktop
app while you are connected, using the same split-tunnel exceptions
you set in the app.</li>
<li>Reports the <b>connected country's</b> location to websites that ask
for your position, instead of your real one. Chromium normally works
your location out from the Wi-Fi networks around you, which a proxy
cannot change -- so this part has to be done in the browser.</li>
<li>Gives you the whole app in the toolbar: every country, connect,
disconnect, the kill switch and the split-tunnel list, in sync with
the app window in both directions.</li>
</ul>
</div>
<div class="card">
<h2>Three things worth knowing</h2>
<ol class="steps">
<li>
<b>It only works while the desktop app is running.</b>
The extension has no VPN of its own -- it points this browser at the
app's engine. With the app closed it goes inert and hands the browser
straight back to your normal connection.
</li>
<li>
<b>Pin it, so it is one click away.</b>
Open the extensions button in the toolbar and use the pin next to
<b>FreeProxy VPN Extension</b>.
</li>
<li>
<b>You do not have to use it.</b>
The desktop app already routes the whole PC. This extension is what
makes the <i>location</i> a website reads match the country you picked,
and what lets you drive the app without leaving the browser.
</li>
</ol>
<div class="toolbar-hint">
<span class="arrow">▲</span>
<img src="icon.png" alt="">
<span>This icon, up in the toolbar, is the extension. Click it any time
to connect, switch country or turn the kill switch on.</span>
</div>
</div>
<div class="card">
<div class="foot">
<button id="ok">Got it</button>
<span class="spacer"></span>
<span class="tiny" id="ver"></span>
</div>
<p class="tiny note">
Removing the desktop app removes this extension with it, along with every
proxy, DNS, IPv6 and location setting it changed. Nothing is left behind.
</p>
</div>
</div>
<script src="welcome.js"></script>
</body>
</html>