main
1/*
2 * noVNC: HTML5 VNC client
3 * Copyright (C) 2019 The noVNC authors
4 * Licensed under MPL 2.0 (see LICENSE.txt)
5 *
6 * See README.md for usage and integration instructions.
7 */
8
9import * as Log from '../core/util/logging.js';
10
11// init log level reading the logging HTTP param
12export function initLogging(level) {
13 "use strict";
14 if (typeof level !== "undefined") {
15 Log.initLogging(level);
16 } else {
17 const param = document.location.href.match(/logging=([A-Za-z0-9._-]*)/);
18 Log.initLogging(param || undefined);
19 }
20}
21
22// Read a query string variable
23// A URL with a query parameter can look like this (But will most probably get logged on the http server):
24// https://www.example.com?myqueryparam=myvalue
25//
26// For privacy (Using a hastag #, the parameters will not be sent to the server)
27// the url can be requested in the following way:
28// https://www.example.com#myqueryparam=myvalue&password=secretvalue
29//
30// Even mixing public and non public parameters will work:
31// https://www.example.com?nonsecretparam=example.com#password=secretvalue
32export function getQueryVar(name, defVal) {
33 "use strict";
34 const re = new RegExp('.*[?&]' + name + '=([^&#]*)'),
35 match = document.location.href.match(re);
36 if (typeof defVal === 'undefined') { defVal = null; }
37
38 if (match) {
39 return decodeURIComponent(match[1]);
40 }
41
42 return defVal;
43}
44
45// Read a hash fragment variable
46export function getHashVar(name, defVal) {
47 "use strict";
48 const re = new RegExp('.*[&#]' + name + '=([^&]*)'),
49 match = document.location.hash.match(re);
50 if (typeof defVal === 'undefined') { defVal = null; }
51
52 if (match) {
53 return decodeURIComponent(match[1]);
54 }
55
56 return defVal;
57}
58
59// Read a variable from the fragment or the query string
60// Fragment takes precedence
61export function getConfigVar(name, defVal) {
62 "use strict";
63 const val = getHashVar(name);
64
65 if (val === null) {
66 return getQueryVar(name, defVal);
67 }
68
69 return val;
70}
71
72/*
73 * Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html
74 */
75
76// No days means only for this browser session
77export function createCookie(name, value, days) {
78 "use strict";
79 let date, expires;
80 if (days) {
81 date = new Date();
82 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
83 expires = "; expires=" + date.toGMTString();
84 } else {
85 expires = "";
86 }
87
88 let secure;
89 if (document.location.protocol === "https:") {
90 secure = "; secure";
91 } else {
92 secure = "";
93 }
94 document.cookie = name + "=" + value + expires + "; path=/" + secure;
95}
96
97export function readCookie(name, defaultValue) {
98 "use strict";
99 const nameEQ = name + "=";
100 const ca = document.cookie.split(';');
101
102 for (let i = 0; i < ca.length; i += 1) {
103 let c = ca[i];
104 while (c.charAt(0) === ' ') {
105 c = c.substring(1, c.length);
106 }
107 if (c.indexOf(nameEQ) === 0) {
108 return c.substring(nameEQ.length, c.length);
109 }
110 }
111
112 return (typeof defaultValue !== 'undefined') ? defaultValue : null;
113}
114
115export function eraseCookie(name) {
116 "use strict";
117 createCookie(name, "", -1);
118}
119
120/*
121 * Setting handling.
122 */
123
124let settings = {};
125
126export function initSettings() {
127 if (!window.chrome || !window.chrome.storage) {
128 settings = {};
129 return Promise.resolve();
130 }
131
132 return new Promise(resolve => window.chrome.storage.sync.get(resolve))
133 .then((cfg) => { settings = cfg; });
134}
135
136// Update the settings cache, but do not write to permanent storage
137export function setSetting(name, value) {
138 settings[name] = value;
139}
140
141// No days means only for this browser session
142export function writeSetting(name, value) {
143 "use strict";
144 if (settings[name] === value) return;
145 settings[name] = value;
146 if (window.chrome && window.chrome.storage) {
147 window.chrome.storage.sync.set(settings);
148 } else {
149 localStorageSet(name, value);
150 }
151}
152
153export function readSetting(name, defaultValue) {
154 "use strict";
155 let value;
156 if ((name in settings) || (window.chrome && window.chrome.storage)) {
157 value = settings[name];
158 } else {
159 value = localStorageGet(name);
160 settings[name] = value;
161 }
162 if (typeof value === "undefined") {
163 value = null;
164 }
165
166 if (value === null && typeof defaultValue !== "undefined") {
167 return defaultValue;
168 }
169
170 return value;
171}
172
173export function eraseSetting(name) {
174 "use strict";
175 // Deleting here means that next time the setting is read when using local
176 // storage, it will be pulled from local storage again.
177 // If the setting in local storage is changed (e.g. in another tab)
178 // between this delete and the next read, it could lead to an unexpected
179 // value change.
180 delete settings[name];
181 if (window.chrome && window.chrome.storage) {
182 window.chrome.storage.sync.remove(name);
183 } else {
184 localStorageRemove(name);
185 }
186}
187
188let loggedMsgs = [];
189function logOnce(msg, level = "warn") {
190 if (!loggedMsgs.includes(msg)) {
191 switch (level) {
192 case "error":
193 Log.Error(msg);
194 break;
195 case "warn":
196 Log.Warn(msg);
197 break;
198 case "debug":
199 Log.Debug(msg);
200 break;
201 default:
202 Log.Info(msg);
203 }
204 loggedMsgs.push(msg);
205 }
206}
207
208let cookiesMsg = "Couldn't access noVNC settings, are cookies disabled?";
209
210function localStorageGet(name) {
211 let r;
212 try {
213 r = localStorage.getItem(name);
214 } catch (e) {
215 if (e instanceof DOMException) {
216 logOnce(cookiesMsg);
217 logOnce("'localStorage.getItem(" + name + ")' failed: " + e,
218 "debug");
219 } else {
220 throw e;
221 }
222 }
223 return r;
224}
225function localStorageSet(name, value) {
226 try {
227 localStorage.setItem(name, value);
228 } catch (e) {
229 if (e instanceof DOMException) {
230 logOnce(cookiesMsg);
231 logOnce("'localStorage.setItem(" + name + "," + value +
232 ")' failed: " + e, "debug");
233 } else {
234 throw e;
235 }
236 }
237}
238function localStorageRemove(name) {
239 try {
240 localStorage.removeItem(name);
241 } catch (e) {
242 if (e instanceof DOMException) {
243 logOnce(cookiesMsg);
244 logOnce("'localStorage.removeItem(" + name + ")' failed: " + e,
245 "debug");
246 } else {
247 throw e;
248 }
249 }
250}