onionshare_cli 2.6.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. onionshare_cli/__init__.py +538 -0
  2. onionshare_cli/censorship.py +311 -0
  3. onionshare_cli/common.py +624 -0
  4. onionshare_cli/meek.py +199 -0
  5. onionshare_cli/mode_settings.py +150 -0
  6. onionshare_cli/onion.py +964 -0
  7. onionshare_cli/onionshare.py +91 -0
  8. onionshare_cli/resources/static/css/style.css +432 -0
  9. onionshare_cli/resources/static/img/ajax.gif +0 -0
  10. onionshare_cli/resources/static/img/favicon.ico +0 -0
  11. onionshare_cli/resources/static/img/logo.png +0 -0
  12. onionshare_cli/resources/static/img/logo_large.png +0 -0
  13. onionshare_cli/resources/static/img/web_file.png +0 -0
  14. onionshare_cli/resources/static/img/web_folder.png +0 -0
  15. onionshare_cli/resources/static/js/chat.js +188 -0
  16. onionshare_cli/resources/static/js/jquery-3.5.1.min.js +2 -0
  17. onionshare_cli/resources/static/js/receive.js +141 -0
  18. onionshare_cli/resources/static/js/send.js +79 -0
  19. onionshare_cli/resources/static/js/socket.io.js +9 -0
  20. onionshare_cli/resources/static/js/socket.io.min.js +7 -0
  21. onionshare_cli/resources/templates/403.html +21 -0
  22. onionshare_cli/resources/templates/404.html +21 -0
  23. onionshare_cli/resources/templates/405.html +21 -0
  24. onionshare_cli/resources/templates/500.html +21 -0
  25. onionshare_cli/resources/templates/chat.html +47 -0
  26. onionshare_cli/resources/templates/denied.html +14 -0
  27. onionshare_cli/resources/templates/listing.html +60 -0
  28. onionshare_cli/resources/templates/receive.html +66 -0
  29. onionshare_cli/resources/templates/send.html +70 -0
  30. onionshare_cli/resources/templates/thankyou.html +27 -0
  31. onionshare_cli/resources/torrc_template +12 -0
  32. onionshare_cli/resources/torrc_template-meek_lite_azure +2 -0
  33. onionshare_cli/resources/torrc_template-obfs4 +12 -0
  34. onionshare_cli/resources/torrc_template-snowflake +3 -0
  35. onionshare_cli/resources/version.txt +1 -0
  36. onionshare_cli/resources/wordlist.txt +7776 -0
  37. onionshare_cli/settings.py +209 -0
  38. onionshare_cli/web/__init__.py +21 -0
  39. onionshare_cli/web/chat_mode.py +190 -0
  40. onionshare_cli/web/receive_mode.py +630 -0
  41. onionshare_cli/web/send_base_mode.py +360 -0
  42. onionshare_cli/web/share_mode.py +599 -0
  43. onionshare_cli/web/web.py +409 -0
  44. onionshare_cli/web/website_mode.py +122 -0
  45. onionshare_cli-2.6.1.dist-info/METADATA +44 -0
  46. onionshare_cli-2.6.1.dist-info/RECORD +48 -0
  47. onionshare_cli-2.6.1.dist-info/WHEEL +4 -0
  48. onionshare_cli-2.6.1.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,91 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ OnionShare | https://onionshare.org/
4
+
5
+ Copyright (C) 2014-2022 Micah Lee, et al. <micah@micahflee.com>
6
+
7
+ This program is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
19
+ """
20
+
21
+ import os
22
+ from .common import AutoStopTimer
23
+
24
+
25
+ class OnionShare(object):
26
+ """
27
+ OnionShare is the main application class. Pass in options and run
28
+ start_onion_service and it will do the magic.
29
+ """
30
+
31
+ def __init__(self, common, onion, local_only=False, autostop_timer=0):
32
+ self.common = common
33
+
34
+ self.common.log("OnionShare", "__init__")
35
+
36
+ # The Onion object
37
+ self.onion = onion
38
+
39
+ self.hidserv_dir = None
40
+ self.onion_host = None
41
+ self.port = None
42
+
43
+ # do not use tor -- for development
44
+ self.local_only = local_only
45
+
46
+ # optionally shut down after N hours
47
+ self.autostop_timer = autostop_timer
48
+ # init auto-stop timer thread
49
+ self.autostop_timer_thread = None
50
+
51
+ def choose_port(self):
52
+ """
53
+ Choose a random port.
54
+ """
55
+ try:
56
+ self.port = self.common.get_available_port(17600, 17650)
57
+ except Exception:
58
+ raise OSError("Cannot find an available OnionShare port")
59
+
60
+ def start_onion_service(self, mode, mode_settings, await_publication=True):
61
+ """
62
+ Start the onionshare onion service.
63
+ """
64
+ self.common.log("OnionShare", "start_onion_service")
65
+
66
+ if not self.port:
67
+ self.choose_port()
68
+
69
+ if self.autostop_timer > 0:
70
+ self.autostop_timer_thread = AutoStopTimer(self.common, self.autostop_timer)
71
+
72
+ if self.local_only:
73
+ self.onion_host = f"127.0.0.1:{self.port}"
74
+ if not mode_settings.get("general", "public"):
75
+ self.auth_string = (
76
+ "E2GOT5LTUTP3OAMRCRXO4GSH6VKJEUOXZQUC336SRKAHTTT5OVSA"
77
+ )
78
+ return
79
+
80
+ self.onion_host = self.onion.start_onion_service(
81
+ mode, mode_settings, self.port, await_publication
82
+ )
83
+
84
+ if not mode_settings.get("general", "public"):
85
+ self.auth_string = self.onion.auth_string
86
+
87
+ def stop_onion_service(self, mode_settings):
88
+ """
89
+ Stop the onion service
90
+ """
91
+ self.onion.stop_onion_service(mode_settings)
@@ -0,0 +1,432 @@
1
+ .clearfix:after {
2
+ content: ".";
3
+ display: block;
4
+ clear: both;
5
+ visibility: hidden;
6
+ line-height: 0;
7
+ height: 0;
8
+ }
9
+
10
+ body {
11
+ margin: 0;
12
+ font-family: Helvetica, sans-serif;
13
+ background-color: #fafafa;
14
+ }
15
+
16
+ .d-flex {
17
+ display: flex;
18
+ flex-wrap: wrap;
19
+ justify-content: space-between;
20
+ align-items: center;
21
+ }
22
+
23
+ header {
24
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
25
+ background: #fff;
26
+ padding: 1rem;
27
+ }
28
+
29
+ header .logo {
30
+ vertical-align: middle;
31
+ width: 3rem;
32
+ height: 3rem;
33
+ }
34
+
35
+ header h1 {
36
+ display: inline-block;
37
+ margin: 0 0 0 0.5rem;
38
+ vertical-align: middle;
39
+ font-weight: normal;
40
+ font-size: 1.375rem;
41
+ color: #333;
42
+ position: relative;
43
+ top: .125rem;
44
+ }
45
+
46
+ header .information {
47
+ font-size: .875rem;
48
+ }
49
+
50
+ .button {
51
+ color: #ffffff;
52
+ background-color: #4e064f;
53
+ padding: .875rem 1rem;
54
+ border: 0;
55
+ border-radius: .25rem;
56
+ text-decoration: none;
57
+ margin-left: 1rem;
58
+ cursor: pointer;
59
+ font-weight: bold;
60
+ }
61
+
62
+ a.button:visited {
63
+ color: #ffffff;
64
+ }
65
+
66
+ .close-button {
67
+ color: #ffffff;
68
+ background-color: #c90c0c;
69
+ padding: 10px;
70
+ border: 0;
71
+ border-radius: 5px;
72
+ text-decoration: none;
73
+ margin-left: 1rem;
74
+ cursor: pointer;
75
+ position: absolute;
76
+ right: 10px;
77
+ bottom: 10px;
78
+ }
79
+
80
+ ul.breadcrumbs {
81
+ display: block;
82
+ list-style: none;
83
+ margin: 10px 0;
84
+ padding: 0;
85
+ }
86
+
87
+ ul.breadcrumbs li {
88
+ display: inline-block;
89
+ list-style: none;
90
+ margin: 0;
91
+ padding: 5px;
92
+ color: #999999;
93
+ }
94
+
95
+ ul.breadcrumbs li span.sep {
96
+ padding-left: 5px;
97
+ }
98
+
99
+ ul.breadcrumbs li a:link, ul.breadcrumbs li a:visited {
100
+ color: #666666;
101
+ border-bottom: 1px solid #666666;
102
+ }
103
+
104
+ .file-list {
105
+ width: 100%;
106
+ margin: 0 auto;
107
+ border-collapse: collapse;
108
+ font-size: .875rem;
109
+ color: #333;
110
+ background-color: #fff;
111
+ }
112
+
113
+ .file-list .heading {
114
+ text-align: left;
115
+ text-transform: uppercase;
116
+ font-weight: normal;
117
+ color: #666666;
118
+ padding: 0.75rem;
119
+ font-size: .75rem;
120
+ letter-spacing: .0625rem;
121
+ }
122
+
123
+ .file-list div.d-flex {
124
+ border-bottom: 1px solid #e0e0e0;
125
+ justify-content: flex-start;
126
+ }
127
+
128
+ .file-list div.d-flex div {
129
+ white-space: nowrap;
130
+ padding: .625rem .75rem;
131
+ }
132
+
133
+ .file-list div.d-flex div img {
134
+ vertical-align: middle;
135
+ margin-right: 0.5rem;
136
+ width: 1.25rem;
137
+ height: 1.25rem;
138
+ }
139
+
140
+ .file-list div.d-flex div:last-child {
141
+ padding-right: 0.75rem;
142
+ flex-basis: 0;
143
+ flex-grow: 1;
144
+ }
145
+
146
+ .file-list div.d-flex div:first-child {
147
+ flex-basis: 0;
148
+ flex-grow: 2;
149
+ }
150
+
151
+ @media (max-width: 950px) {
152
+ .file-list div.d-flex div:last-child {
153
+ flex-basis: auto;
154
+ flex-grow: 0;
155
+ }
156
+ }
157
+
158
+ @media (max-width: 655px) {
159
+ .header {
160
+ padding: 0 1rem;
161
+ }
162
+ .file-list {
163
+ font-size: .9375rem;
164
+ }
165
+ .file-list div.d-flex {
166
+ display: block;
167
+ }
168
+ .file-list div.d-flex span {
169
+ max-width: 100%;
170
+ word-break: break-all;
171
+ white-space: normal;
172
+ vertical-align: top;
173
+ }
174
+ .file-list div.d-flex #size-header {
175
+ display: none;
176
+ }
177
+ .file-list div.d-flex div:last-child {
178
+ padding-left: 3.75rem;
179
+ font-size: 0.75rem;
180
+ padding-top: 0;
181
+ margin-top: -.5rem;
182
+ color: #666;
183
+ }
184
+ .d-flex .row div:first-of-type {
185
+ padding-bottom: 0;
186
+ }
187
+ }
188
+
189
+ @media (max-width: 500px) {
190
+ header .information {
191
+ width: 100%;
192
+ align-items: end;
193
+ }
194
+
195
+ .file-list div.d-flex div {
196
+ white-space: nowrap;
197
+ padding: .625rem 1rem;
198
+ }
199
+ }
200
+
201
+ .chat-container {
202
+ display: flex;
203
+ font-family: monospace;
204
+ }
205
+
206
+ .chat-users {
207
+ width: 20%;
208
+ border: 1px solid rgba(0, 0, 0, 0.1);
209
+ border-radius: 2px;
210
+ overflow: auto;
211
+ background: #f2f2f2;
212
+ margin: 1rem 0 1rem 1rem;
213
+ }
214
+
215
+ .chat-users .editable-username {
216
+ display: flex;
217
+ padding: 1rem;
218
+ flex-direction: column;
219
+ }
220
+
221
+ .chat-users .editable-username input {
222
+ font-family: monospace;
223
+ font-size: 1em;
224
+ }
225
+
226
+ .chat-users .editable-username #username-error {
227
+ color: #c90c0c;
228
+ margin: 0.5rem;
229
+ }
230
+
231
+ .chat-users #user-list li {
232
+ margin-bottom: 1em;
233
+ }
234
+
235
+ .chat-wrapper {
236
+ display: flex;
237
+ flex-direction: column;
238
+ flex: 1;
239
+ margin: 1rem 1rem 0 1rem;
240
+ height: calc(100vh - (65px + 2em));
241
+ }
242
+
243
+ .chat-wrapper #chat {
244
+ border: 1px solid rgba(0, 0, 0, 0.1);
245
+ border-radius: 2px;
246
+ flex: 1;
247
+ overflow: auto;
248
+ background: #f2f2f2;
249
+ padding: 0 1rem;
250
+ }
251
+
252
+ .chat-wrapper .status {
253
+ font-style: italic;
254
+ font-size: 0.8em;
255
+ color: #666666;
256
+ }
257
+
258
+ .chat-wrapper .username {
259
+ font-weight: bold;
260
+ display: block;
261
+ }
262
+ .chat-wrapper .message {
263
+ word-break: break-word;
264
+ font-weight: normal;
265
+ display: block;
266
+ margin-bottom: 0.3em;
267
+ }
268
+
269
+ .chat-wrapper .chat-form {
270
+ display: block;
271
+ margin: 0.2rem 1rem 1rem 0;
272
+ padding: -0.5em;
273
+ }
274
+
275
+ .chat-wrapper input#new-message {
276
+ height: 100%;
277
+ width: 100%;
278
+ font-family: monospace;
279
+ font-size: 1em;
280
+ }
281
+
282
+ @media (max-width: 992px) {
283
+ .chat-users .editable-username {
284
+ display: block;
285
+ }
286
+
287
+ .chat-users input#username {
288
+ width: 90%;
289
+ }
290
+ }
291
+
292
+ .no-js {
293
+ display: none;
294
+ }
295
+
296
+ .upload-wrapper {
297
+ align-items: center;
298
+ justify-content: center;
299
+ min-height: 400px;
300
+ text-align: center;
301
+ }
302
+
303
+ .upload-wrapper img.logo {
304
+ width: 120px;
305
+ height: 120px;
306
+ }
307
+
308
+ .upload-wrapper .upload-header {
309
+ font-size: 30px;
310
+ font-weight: normal;
311
+ color: #666666;
312
+ margin: 0 0 10px 0;
313
+ }
314
+
315
+ .upload-wrapper .upload-description {
316
+ color: #666666;
317
+ margin: 0 0 20px 0;
318
+ }
319
+
320
+ .upload-wrapper textarea {
321
+ max-width: 95%;
322
+ width: 600px;
323
+ height: 150px;
324
+ padding: 10px;
325
+ }
326
+
327
+ div#uploads {
328
+ width: 800px;
329
+ max-width: 90%;
330
+ margin: 0 auto;
331
+ }
332
+
333
+ div#uploads .upload {
334
+ border: 1px solid #DDDDDD;
335
+ margin: 20px 0;
336
+ padding: 10px;
337
+ text-align: left;
338
+ }
339
+
340
+ div#uploads .upload .upload-filename {
341
+ font-weight: bold;
342
+ font-family: monospace;
343
+ font-size: 1.1em;
344
+ margin-bottom: 5px;
345
+ }
346
+
347
+ div#uploads .upload .upload-status {
348
+ color: #999999;
349
+ font-size: 0.9em;
350
+ margin-bottom: 5px;
351
+ }
352
+
353
+ div#uploads .upload input.cancel {
354
+ color: #d0011b;
355
+ border: 0;
356
+ background: none;
357
+ box-shadow: none;
358
+ border-radius: 0px;
359
+ cursor: pointer;
360
+ font-family: sans-serif;
361
+ font-size: 12px;
362
+ text-decoration: none;
363
+ display: inline-block;
364
+ float:right;
365
+ }
366
+
367
+ div#uploads .upload progress {
368
+ width: 100%;
369
+ height: 20px;
370
+ }
371
+
372
+ ul.flashes {
373
+ list-style: none;
374
+ margin: 0;
375
+ padding: 0;
376
+ width: 800px;
377
+ max-width: 100%;
378
+ margin: 0 auto;
379
+ }
380
+
381
+ ul.flashes li {
382
+ margin: 0 0 5px 0;
383
+ padding: 5px;
384
+ list-style: none;
385
+ text-align: center;
386
+ word-break: break-word;
387
+ }
388
+
389
+ li.error {
390
+ color: #d0011b;
391
+ }
392
+
393
+ li.info {
394
+ color: #5fa416;
395
+ }
396
+
397
+ .closed-wrapper {
398
+ display: flex;
399
+ align-items: center;
400
+ justify-content: center;
401
+ min-height: 400px;
402
+ }
403
+
404
+ .info {
405
+ text-align: center;
406
+ }
407
+
408
+ .info img {
409
+ width: 120px;
410
+ height: 120px;
411
+ }
412
+
413
+ .info .info-header {
414
+ font-size: 30px;
415
+ font-weight: normal;
416
+ color: #666666;
417
+ margin: 0 0 10px 0;
418
+ }
419
+
420
+ .info .info-description {
421
+ color: #666666;
422
+ margin: 0 0 20px 0;
423
+ }
424
+
425
+ a {
426
+ text-decoration: none;
427
+ color: #1c1ca0;
428
+ }
429
+
430
+ a:visited {
431
+ color: #601ca0;
432
+ }
@@ -0,0 +1,188 @@
1
+ $(function () {
2
+ $(document).ready(function () {
3
+ $('.chat-container').removeClass('no-js');
4
+ var socket = io.connect(
5
+ 'http://' + document.domain + ':' + location.port + '/chat',
6
+ {
7
+ transports: ['websocket']
8
+ }
9
+ );
10
+
11
+ // Store current username received from app context
12
+ var current_username = $('#username').val().trim();
13
+
14
+ // Triggered on any status change by any user, such as some
15
+ // user joined, or changed username, or left, etc.
16
+ socket.on('status', function (data) {
17
+ addMessageToPanel(data, current_username, 'status');
18
+ console.log(data, current_username);
19
+ });
20
+
21
+ // Triggered when message is received from a user. Even when sent
22
+ // by self, it get triggered after the server sends back the emit.
23
+ socket.on('chat_message', function (data) {
24
+ addMessageToPanel(data, current_username, 'chat');
25
+ console.log(data, current_username);
26
+ });
27
+
28
+ // Triggered when disconnected either by server stop or timeout
29
+ socket.on('disconnect', function (data) {
30
+ addMessageToPanel({ 'msg': 'The chat server is disconnected.' }, current_username, 'status');
31
+ })
32
+ socket.on('connect_error', function (error) {
33
+ console.log("error");
34
+ })
35
+
36
+ // Trigger new message on enter or click of send message button.
37
+ $('#new-message').on('keypress', function (e) {
38
+ var code = e.keyCode || e.which;
39
+ if (code == 13) {
40
+ emitMessage(socket);
41
+ }
42
+ });
43
+
44
+ // Keep buttons disabled unless changed or not empty
45
+ $('#username').on('keyup', function (event) {
46
+ if ($('#username').val() !== '' && $('#username').val() !== current_username) {
47
+ if (event.keyCode == 13 || event.which == 13) {
48
+ this.blur();
49
+ current_username = updateUsername(socket) || current_username;
50
+ }
51
+ }
52
+ });
53
+
54
+ // Show warning of losing data
55
+ $(window).on('beforeunload', function (e) {
56
+ e.preventDefault();
57
+ e.returnValue = '';
58
+ return '';
59
+ });
60
+ });
61
+ });
62
+
63
+ var addMessageToPanel = function (data, current_username, messageType) {
64
+ var scrollDiff = getScrollDiffBefore();
65
+ if (messageType === 'status') {
66
+ addStatusMessage(data.msg);
67
+ if (data.connected_users) {
68
+ addUserList(data.connected_users, current_username);
69
+ }
70
+ } else if (messageType === 'chat') {
71
+ addChatMessage(data.username, data.msg)
72
+ }
73
+ scrollBottomMaybe(scrollDiff);
74
+ }
75
+
76
+ var emitMessage = function (socket) {
77
+ var text = $('#new-message').val();
78
+ $('#new-message').val('');
79
+ $('#chat').scrollTop($('#chat')[0].scrollHeight);
80
+ socket.emit('text', { msg: text });
81
+ }
82
+
83
+ var updateUsername = function (socket) {
84
+ var username = $('#username').val();
85
+ if (!checkUsernameExists(username) && !checkUsernameTooLong(username) && !checkUsernameAscii(username)) {
86
+ $.ajax({
87
+ method: 'POST',
88
+ url: `http://${document.domain}:${location.port}/update-session-username`,
89
+ contentType: 'application/json',
90
+ dataType: 'json',
91
+ data: JSON.stringify({ 'username': username })
92
+ }).done(function (response) {
93
+ console.log(response);
94
+ if (response.success && response.username == username) {
95
+ socket.emit('update_username', { username: username });
96
+ } else {
97
+ addStatusMessage("Failed to update username.")
98
+ }
99
+ });
100
+ return username;
101
+ }
102
+ return false;
103
+ }
104
+
105
+ /************************************/
106
+ /********* Util Functions ***********/
107
+ /************************************/
108
+
109
+ var createUserListHTML = function (connected_users, current_user) {
110
+ var userListHTML = '';
111
+ connected_users.sort();
112
+ connected_users.forEach(function (username) {
113
+ if (username !== current_user) {
114
+ userListHTML += `<li>${sanitizeHTML(username)}</li>`;
115
+ }
116
+ });
117
+ return userListHTML;
118
+ }
119
+
120
+ var checkUsernameAscii = function (username) {
121
+ // ASCII characters have code points in the range U+0000-U+007F.
122
+ $('#username-error').text('');
123
+ if (!/^[\u0000-\u007f]*$/.test(username)) {
124
+ $('#username-error').text('Non-ASCII usernames are not supported.');
125
+ return true;
126
+ }
127
+ return false;
128
+ }
129
+
130
+ var checkUsernameExists = function (username) {
131
+ $('#username-error').text('');
132
+ var userMatches = $('#user-list li').filter(function () {
133
+ return $(this).text() === username;
134
+ });
135
+ if (userMatches.length) {
136
+ $('#username-error').text('User with that username exists!');
137
+ return true;
138
+ }
139
+ return false;
140
+ }
141
+
142
+ var checkUsernameTooLong = function (username) {
143
+ $('#username-error').text('');
144
+ if (username.length > 128) {
145
+ $('#username-error').text('Please choose a shorter username.');
146
+ return true;
147
+ }
148
+ return false;
149
+ }
150
+
151
+ var getScrollDiffBefore = function () {
152
+ return $('#chat').scrollTop() - ($('#chat')[0].scrollHeight - $('#chat')[0].offsetHeight);
153
+ }
154
+
155
+ var scrollBottomMaybe = function (scrollDiff) {
156
+ // Scrolls to bottom if the user is scrolled at bottom
157
+ // if the user has scrolled up, it won't scroll at bottom.
158
+ // Note: when a user themselves send a message, it will still
159
+ // scroll to the bottom even if they had scrolled up before.
160
+ if (scrollDiff > 0) {
161
+ $('#chat').scrollTop($('#chat')[0].scrollHeight);
162
+ }
163
+ }
164
+
165
+ var addStatusMessage = function (message) {
166
+ $('#chat').append(
167
+ `<p class="status">${sanitizeHTML(message)}</p>`
168
+ );
169
+ }
170
+
171
+ var addChatMessage = function (username, message) {
172
+ $('#chat').append(`<p><span class="username">${sanitizeHTML(username)}</span><span class="message">${sanitizeHTML(message)}</span></p>`);
173
+ }
174
+
175
+ var addUserList = function (connected_users, current_username) {
176
+ $('#user-list').html(
177
+ createUserListHTML(
178
+ connected_users,
179
+ current_username
180
+ )
181
+ );
182
+ }
183
+
184
+ var sanitizeHTML = function (str) {
185
+ var temp = document.createElement('span');
186
+ temp.textContent = str;
187
+ return temp.innerHTML;
188
+ };