Skip to content

Commit 7f9a38d

Browse files
committedFeb 18, 2021
Refactoring JavaScript across seven files and adding tooltips
1 parent f3ae218 commit 7f9a38d

12 files changed

+745
-727
lines changed
 

‎.babelrc

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"presets": "es2015"
3+
}

‎core.css

+2-2
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ a#version-number {
263263
}
264264

265265
.skyid-logo {
266-
height: 18px;
267-
width: 18px;
266+
height: 16px;
267+
width: 16px;
268268
vertical-align: middle;
269269
margin-right: 2px;
270270
}

‎index.html

+65-31
Large diffs are not rendered by default.

‎package-lock.json

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"stream-browserify": "^3.0.0"
1818
},
1919
"devDependencies": {
20+
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
2021
"@rollup/plugin-node-resolve": "^11.0.1",
2122
"webpack": "^5.11.0",
2223
"webpack-cli": "^4.2.0"

‎src/account.js

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*jshint esversion: 8 */
2+
3+
import MicroModal from 'micromodal';
4+
import { loadMyPastes, myPastes }
5+
from './editor.js';
6+
import { encryptObjectToJSON, decryptJSONToObject }
7+
from './encryption.js';
8+
import { byId, clickListener, deleteClickListener }
9+
from './interface.js';
10+
import { generateDocKey, getPubkeyBasedRetrievalString }
11+
from './utility.js';
12+
13+
export var username;
14+
export var pubkey;
15+
16+
const switchToLoggedIn = (message) => {
17+
if (message == "login_success") {
18+
byId("button-log-out").style.display = "inline-block";
19+
byId("save-to-my-pastes-button").style.display = "inline-block";
20+
byId("modal-content").innerHTML =
21+
"<p>Setting up your Hacker Paste account...</p>";
22+
MicroModal.show('app-modal');
23+
skyid.getRegistry('hackerpaste:username', (response) => {
24+
if (response.entry === null) {
25+
username = prompt("What should we call you?");
26+
skyid.setRegistry('hackerpaste:username', username, () =>
27+
location.reload());
28+
} else {
29+
username = response.entry.data;
30+
skyid.getProfile((response2) => {
31+
response2 = JSON.parse(response2);
32+
pubkey = response2.dapps["Hacker Paste"].publicKey;
33+
byId("username").textContent = username;
34+
byId("button-username").setAttribute('aria-label', 'View My Pastes');
35+
skyid.getJSON('hackerpaste:my-pastes', (response3) => {
36+
if (response3 !== "") {
37+
myPastes = decryptJSONToObject(response3, skyid.seed);
38+
deleteClickListener("button-username", startSkyIDSession);
39+
clickListener("button-username", loadMyPastes);
40+
MicroModal.close('app-modal');
41+
} else {
42+
let noteToSelf = getPubkeyBasedRetrievalString(
43+
pubkey) + generateDocKey();
44+
let defaultContent =
45+
{documents:[{label:"Note to Self",docID:noteToSelf}]};
46+
defaultContent = encryptObjectToJSON(defaultContent, skyid.seed);
47+
skyid.setJSON('hackerpaste:my-pastes',
48+
defaultContent, () => location.reload());
49+
}
50+
});
51+
});
52+
}
53+
});
54+
}
55+
};
56+
57+
export var skyid = new SkyID('Hacker Paste', switchToLoggedIn, {
58+
devMode: false
59+
});
60+
61+
if (skyid.seed != "") switchToLoggedIn("login_success");
62+
63+
export const startSkyIDSession = () => skyid.sessionStart();
64+
65+
export const switchToLoggedOut = () => {
66+
skyid.sessionDestroy();
67+
byId("username").textContent = "Sign in with SkyID";
68+
clickListener("button-username", startSkyIDSession);
69+
deleteClickListener("button-username", loadMyPastes);
70+
byId("button-log-out").style.display = "none";
71+
byId("save-to-my-pastes-button").style.display = "none";
72+
byId("button-username").setAttribute('aria-label',
73+
'Sign in to keep your own private paste list. Registration is completely anonymous.');
74+
};

‎src/editor.js

+338
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
/*jshint esversion: 8 */
2+
3+
import ClipboardJS from 'clipboard';
4+
import CodeMirror from 'codemirror';
5+
import SlimSelect from 'slim-select';
6+
import marked from 'marked';
7+
import { skyid, pubkey } from './account.js';
8+
import { decryptData, encryptObjectToJSON } from './encryption.js';
9+
import { byId, byClass, hideCopyBar, backToEditor, clickListener }
10+
from './interface.js';
11+
import { buildUrl } from './links.js';
12+
import { shorten, base64ToHex } from './utility.js';
13+
14+
import 'codemirror/addon/mode/loadmode';
15+
import 'codemirror/addon/mode/overlay';
16+
import 'codemirror/addon/mode/multiplex';
17+
import 'codemirror/addon/mode/simple';
18+
import 'codemirror/addon/scroll/simplescrollbars';
19+
import 'codemirror/mode/meta';
20+
import 'codemirror/mode/apl/apl';
21+
import 'codemirror/mode/asciiarmor/asciiarmor';
22+
import 'codemirror/mode/asn.1/asn.1';
23+
import 'codemirror/mode/asterisk/asterisk';
24+
import 'codemirror/mode/brainfuck/brainfuck';
25+
import 'codemirror/mode/clike/clike';
26+
import 'codemirror/mode/clojure/clojure';
27+
import 'codemirror/mode/cmake/cmake';
28+
import 'codemirror/mode/cobol/cobol';
29+
import 'codemirror/mode/coffeescript/coffeescript';
30+
import 'codemirror/mode/commonlisp/commonlisp';
31+
import 'codemirror/mode/crystal/crystal';
32+
import 'codemirror/mode/css/css';
33+
import 'codemirror/mode/cypher/cypher';
34+
import 'codemirror/mode/d/d';
35+
import 'codemirror/mode/dart/dart';
36+
import 'codemirror/mode/diff/diff';
37+
import 'codemirror/mode/django/django';
38+
import 'codemirror/mode/dockerfile/dockerfile';
39+
import 'codemirror/mode/dtd/dtd';
40+
import 'codemirror/mode/dylan/dylan';
41+
import 'codemirror/mode/ebnf/ebnf';
42+
import 'codemirror/mode/ecl/ecl';
43+
import 'codemirror/mode/eiffel/eiffel';
44+
import 'codemirror/mode/elm/elm';
45+
import 'codemirror/mode/erlang/erlang';
46+
import 'codemirror/mode/factor/factor';
47+
import 'codemirror/mode/fcl/fcl';
48+
import 'codemirror/mode/forth/forth';
49+
import 'codemirror/mode/fortran/fortran';
50+
import 'codemirror/mode/gas/gas';
51+
import 'codemirror/mode/gfm/gfm';
52+
import 'codemirror/mode/gherkin/gherkin';
53+
import 'codemirror/mode/go/go';
54+
import 'codemirror/mode/groovy/groovy';
55+
import 'codemirror/mode/haml/haml';
56+
import 'codemirror/mode/handlebars/handlebars';
57+
import 'codemirror/mode/haskell/haskell';
58+
import 'codemirror/mode/haskell-literate/haskell-literate';
59+
import 'codemirror/mode/haxe/haxe';
60+
import 'codemirror/mode/htmlembedded/htmlembedded';
61+
import 'codemirror/mode/htmlmixed/htmlmixed';
62+
import 'codemirror/mode/http/http';
63+
import 'codemirror/mode/idl/idl';
64+
import 'codemirror/mode/javascript/javascript';
65+
import 'codemirror/mode/jinja2/jinja2';
66+
import 'codemirror/mode/jsx/jsx';
67+
import 'codemirror/mode/julia/julia';
68+
import 'codemirror/mode/livescript/livescript';
69+
import 'codemirror/mode/lua/lua';
70+
import 'codemirror/mode/markdown/markdown';
71+
import 'codemirror/mode/mathematica/mathematica';
72+
import 'codemirror/mode/mbox/mbox';
73+
import 'codemirror/mode/mirc/mirc';
74+
import 'codemirror/mode/mllike/mllike';
75+
import 'codemirror/mode/modelica/modelica';
76+
import 'codemirror/mode/mscgen/mscgen';
77+
import 'codemirror/mode/mumps/mumps';
78+
import 'codemirror/mode/nginx/nginx';
79+
import 'codemirror/mode/nsis/nsis';
80+
import 'codemirror/mode/ntriples/ntriples';
81+
import 'codemirror/mode/octave/octave';
82+
import 'codemirror/mode/oz/oz';
83+
import 'codemirror/mode/pascal/pascal';
84+
import 'codemirror/mode/pegjs/pegjs';
85+
import 'codemirror/mode/perl/perl';
86+
import 'codemirror/mode/php/php';
87+
import 'codemirror/mode/pig/pig';
88+
import 'codemirror/mode/powershell/powershell';
89+
import 'codemirror/mode/properties/properties';
90+
import 'codemirror/mode/protobuf/protobuf';
91+
import 'codemirror/mode/pug/pug';
92+
import 'codemirror/mode/puppet/puppet';
93+
import 'codemirror/mode/python/python';
94+
import 'codemirror/mode/q/q';
95+
import 'codemirror/mode/r/r';
96+
import 'codemirror/mode/rpm/rpm';
97+
import 'codemirror/mode/rst/rst';
98+
import 'codemirror/mode/ruby/ruby';
99+
import 'codemirror/mode/rust/rust';
100+
import 'codemirror/mode/sas/sas';
101+
import 'codemirror/mode/sass/sass';
102+
import 'codemirror/mode/scheme/scheme';
103+
import 'codemirror/mode/shell/shell';
104+
import 'codemirror/mode/sieve/sieve';
105+
import 'codemirror/mode/slim/slim';
106+
import 'codemirror/mode/smalltalk/smalltalk';
107+
import 'codemirror/mode/smarty/smarty';
108+
import 'codemirror/mode/solr/solr';
109+
import 'codemirror/mode/soy/soy';
110+
import 'codemirror/mode/sparql/sparql';
111+
import 'codemirror/mode/spreadsheet/spreadsheet';
112+
import 'codemirror/mode/sql/sql';
113+
import 'codemirror/mode/stex/stex';
114+
import 'codemirror/mode/stylus/stylus';
115+
import 'codemirror/mode/swift/swift';
116+
import 'codemirror/mode/tcl/tcl';
117+
import 'codemirror/mode/textile/textile';
118+
import 'codemirror/mode/tiddlywiki/tiddlywiki';
119+
import 'codemirror/mode/tiki/tiki';
120+
import 'codemirror/mode/toml/toml';
121+
import 'codemirror/mode/tornado/tornado';
122+
import 'codemirror/mode/troff/troff';
123+
import 'codemirror/mode/ttcn/ttcn';
124+
import 'codemirror/mode/ttcn-cfg/ttcn-cfg';
125+
import 'codemirror/mode/turtle/turtle';
126+
import 'codemirror/mode/twig/twig';
127+
import 'codemirror/mode/vb/vb';
128+
import 'codemirror/mode/vbscript/vbscript';
129+
import 'codemirror/mode/velocity/velocity';
130+
import 'codemirror/mode/verilog/verilog';
131+
import 'codemirror/mode/vhdl/vhdl';
132+
import 'codemirror/mode/vue/vue';
133+
import 'codemirror/mode/wast/wast';
134+
import 'codemirror/mode/webidl/webidl';
135+
import 'codemirror/mode/xml/xml';
136+
import 'codemirror/mode/xquery/xquery';
137+
import 'codemirror/mode/yacas/yacas';
138+
import 'codemirror/mode/yaml/yaml';
139+
import 'codemirror/mode/yaml-frontmatter/yaml-frontmatter';
140+
import 'codemirror/mode/z80/z80';
141+
142+
export var clipboard;
143+
export var editor;
144+
export var select;
145+
export var myPastes;
146+
export var docLabel;
147+
export var persistentDocKey;
148+
export var statsEl;
149+
150+
const gameRoom =
151+
"AAAuytkzAUZHtJfNKENEj4A9HAvne4fGaKBLONkWGQ01vgvn6zv0Zd2HQGT89wuAy1";
152+
153+
const initCode = () => {
154+
let payload = location.hash.substr(1);
155+
if (payload.length === 0) return;
156+
payload = payload.split(".");
157+
let docID = payload[0];
158+
loadByDocID(docID);
159+
};
160+
161+
const initClipboard = () => {
162+
clipboard = new ClipboardJS(".clipboard");
163+
clipboard.on("success", () => {
164+
hideCopyBar(true);
165+
});
166+
};
167+
168+
const initModals = () => {
169+
MicroModal.init({
170+
onClose: () => editor.focus(),
171+
});
172+
};
173+
174+
export const initCodeEditor = () => {
175+
persistentDocKey = null;
176+
docLabel = null;
177+
editor = new CodeMirror(byId("editor"), {
178+
lineNumbers: true,
179+
theme: "dracula",
180+
readOnly: readOnly,
181+
lineWrapping: true,
182+
scrollbarStyle: "simple",
183+
});
184+
if (readOnly) {
185+
document.body.classList.add("readonly");
186+
}
187+
statsEl = byId("stats");
188+
editor.on("change", () => {
189+
statsEl.innerHTML = `Length: ${editor.getValue().length} | Lines: ${
190+
editor.doc.size
191+
}`;
192+
hideCopyBar();
193+
});
194+
};
195+
196+
const initLangSelector = () => {
197+
select = new SlimSelect({
198+
select: "#language",
199+
data: CodeMirror.modeInfo.map((e) => ({
200+
text: e.name,
201+
value: shorten(e.name),
202+
data: {
203+
mime: e.mime,
204+
mode: e.mode
205+
},
206+
})),
207+
showContent: "down",
208+
onChange: (e) => {
209+
const language = e.data || {
210+
mime: null,
211+
mode: null
212+
};
213+
editor.setOption("mode", language.mime);
214+
CodeMirror.autoLoadMode(editor, language.mode);
215+
document.title =
216+
e.text && e.text !== "Plain Text" ?
217+
`Hacker Paste - ${e.text} code snippet` :
218+
"Hacker Paste";
219+
},
220+
});
221+
222+
// Set lang selector
223+
const l = location.hash.substr(1).split(".")[1] ||
224+
new URLSearchParams(window.location.search).get("l");
225+
select.set(l ? decodeURIComponent(l) : shorten("Plain Text"));
226+
};
227+
228+
export const init = () => {
229+
initCodeEditor();
230+
initLangSelector();
231+
initCode();
232+
initClipboard();
233+
initModals();
234+
};
235+
236+
export const disableLineWrapping = () => {
237+
byId("disable-line-wrapping").classList.add("hidden");
238+
byId("enable-line-wrapping").classList.remove("hidden");
239+
editor.setOption("lineWrapping", false);
240+
};
241+
242+
export const enableLineWrapping = () => {
243+
byId("enable-line-wrapping").classList.add("hidden");
244+
byId("disable-line-wrapping").classList.remove("hidden");
245+
editor.setOption("lineWrapping", true);
246+
};
247+
248+
const loadByDocID = (docID) => {
249+
// A `docID` is a document's retrieval string plus its decryption string.
250+
// A file suffix for syntax highlighting does not count as part of the docID.
251+
// Different varieties of docID can be distinguished by their lengths:
252+
//
253+
// * 46 characters: unencrypted, immutable files identified by skylink (as
254+
// produced by very early versions of Hacker Paste). Hacker Paste will
255+
// open all valid skylinks that are text-based files.
256+
// * 64 characters: encrypted, mutable SkyDB files. The skylink representing
257+
// the latest version is posted to the SkyDB entry, with the user's public
258+
// key, a 64-character hex string, padded with '00' at the end and
259+
// re-encoded as a 44-character base64 string. The following 20 characters
260+
// are used to decrypt the file. These are "my pastes" links.
261+
// * 66 characters: encrypted, immutable skyfiles. The first 46 characters
262+
// identifies the skyfile while the remaining 20 characters decrypt the
263+
// file. These are "snapshot" links.
264+
265+
var skylink;
266+
var docKey;
267+
268+
persistentDocKey = null;
269+
docLabel = null;
270+
271+
if (docID === "A".repeat(66)) docID = gameRoom;
272+
273+
if (docID.length === 46) loadSkylink(docID);
274+
else if (docID.length === 66) {
275+
docKey = docID.substr(46);
276+
skylink = docID.substr(0, 46);
277+
loadSkylink(skylink, docKey);
278+
} else if (docID.length == 64) {
279+
docKey = docID.substr(44);
280+
persistentDocKey = docKey;
281+
let docPubkey = base64ToHex(docID.substr(0, 44)).substr(0, 64);
282+
skyid.skynetClient.registry.getEntry(docPubkey,
283+
`hackerpaste:file:${docKey}`)
284+
.then((result) => {
285+
console.log(result);
286+
skylink = result.entry.data;
287+
loadSkylink(skylink, docKey);
288+
})
289+
.catch((error) => {
290+
console.error(error);
291+
});
292+
} else alert('This is not a valid paste link.');
293+
};
294+
295+
const loadView = (viewContent) => {
296+
editor.setOption('readOnly', true);
297+
byClass("CodeMirror-cursors").setAttribute("style", "display:none;");
298+
byClass("CodeMirror-code").innerHTML =
299+
`<div style="font-size:110%; margin:0;">${viewContent}</div>`;
300+
};
301+
302+
const loadSkylink = (skylink, docKey) => {
303+
fetch(`/${skylink}`)
304+
.then((response) => response.text())
305+
.then((data) => {
306+
if (docKey) data = decryptData(data, docKey);
307+
if (skylink === gameRoom.substr(0, 46)) {
308+
loadView(marked(data));
309+
} else editor.setValue(data);
310+
})
311+
.catch((error) => {
312+
console.error("Error:", error);
313+
});
314+
};
315+
316+
export const loadGameRoom = () => loadByDocID(gameRoom);
317+
318+
export const loadMyPastes = () => {
319+
let view = "<ul id='my-pastes-list'>";
320+
for (let i = 0; i < myPastes.documents.length; i++) {
321+
let entryURL = buildUrl(myPastes.documents[i].docID, "mypastes", "");
322+
view +=
323+
`<li><a href="${entryURL.url}" target="_blank">${myPastes.documents[i].label}</a></li>`;
324+
};
325+
view += "</ul><br />";
326+
view += `<button id="new-paste-button" class="py-1 px-2 mx-0 my-1" type="button">New Paste</button>`;
327+
loadView(view);
328+
clickListener("new-paste-button", backToEditor);
329+
};
330+
331+
export async function updateMyPastes(docID) {
332+
myPastes.documents.push({label: docLabel, docID: docID});
333+
let newPasteList = encryptObjectToJSON(myPastes, skyid.seed);
334+
console.log("newPasteList: " + newPasteList);
335+
skyid.setJSON('hackerpaste:my-pastes', newPasteList, (response) => {
336+
if (response !== true) console.log(response);
337+
})
338+
}

‎src/encryption.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* jshint esversion: 8 */
2+
3+
import CryptoJS from 'crypto-js';
4+
5+
export const encryptData = (data, docKey) => CryptoJS.AES.encrypt(data, docKey);
6+
7+
export const decryptData = (data, docKey) =>
8+
CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(data, docKey));
9+
10+
export const encryptObjectToJSON = (data, seed) => {
11+
data = JSON.stringify(data);
12+
let encryptedData = encryptData(data, seed);
13+
data = {encrypted:encryptedData.toString()};
14+
data = JSON.stringify(data);
15+
return data;
16+
};
17+
18+
export const decryptJSONToObject = (data, seed) =>
19+
JSON.parse(decryptData(JSON.parse(data).encrypted, seed));

‎src/index.js

+20-616
Large diffs are not rendered by default.

‎src/interface.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*jshint esversion: 8 */
2+
3+
import { initCodeEditor } from './editor.js';
4+
5+
export const byId = (id) => document.getElementById(id);
6+
7+
export const byClass = (id) => document.getElementsByClassName(id)[0];
8+
9+
export const clickListener = (element_id, func) =>
10+
byId(element_id).addEventListener("click", func);
11+
12+
export const deleteClickListener = (element_id, func) =>
13+
byId(element_id).removeEventListener("click", func);
14+
15+
// Open the "Copy" bar and select the content
16+
export const showCopyBar = (dataToCopy) => {
17+
byId("copy").classList.remove("hidden");
18+
const linkInput = byId("copy-link");
19+
linkInput.value = dataToCopy;
20+
linkInput.focus();
21+
linkInput.setSelectionRange(0, dataToCopy.length);
22+
};
23+
24+
// Close the "Copy" bar
25+
export const hideCopyBar = (success) => {
26+
const copyButton = byId("copy-btn");
27+
const copyBar = byId("copy");
28+
if (!success) {
29+
copyBar.classList.add("hidden");
30+
return;
31+
}
32+
copyButton.innerText = "Copied !";
33+
setTimeout(() => {
34+
copyBar.classList.add("hidden");
35+
copyButton.innerText = "Copy";
36+
}, 800);
37+
};
38+
39+
export const hideCopyBarNow = () => hideCopyBar(false);
40+
41+
export const backToEditor = () => {
42+
byId("editor").innerHTML = "";
43+
initCodeEditor();
44+
};

‎src/links.js

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*jshint esversion: 8 */
2+
3+
import { skyid, pubkey } from './account.js';
4+
import { editor, docLabel, persistentDocKey, myPastes, updateMyPastes, select }
5+
from './editor.js';
6+
import { encryptData } from './encryption.js';
7+
import { showCopyBar } from './interface.js';
8+
import { shorten, generateDocKey, generateUuid, getPubkeyBasedRetrievalString }
9+
from './utility.js';
10+
11+
const generateLink = (mode) => {
12+
let docKey;
13+
let retrievalString;
14+
if (mode === 'mypastes') {
15+
docKey = persistentDocKey || generateDocKey();
16+
persistentDocKey = docKey;
17+
} else {
18+
docKey = generateDocKey();
19+
}
20+
21+
const data = editor.getValue();
22+
const encryptedData = encryptData(data, docKey);
23+
showCopyBar('Uploading...');
24+
var blob = new Blob(
25+
[encryptedData], {
26+
type: "text/plain",
27+
encoding: "utf-8"
28+
}
29+
);
30+
var formData = new FormData();
31+
formData.append("file", blob);
32+
const uuid = generateUuid();
33+
fetch(`/skynet/skyfile/${uuid}?filename=paste.txt`, {
34+
method: "POST",
35+
body: formData,
36+
})
37+
.then((response) => response.json())
38+
.then((result) => {
39+
if (mode !== 'mypastes') retrievalString = result.skylink;
40+
else retrievalString = getPubkeyBasedRetrievalString(pubkey);
41+
var url = buildUrl(retrievalString, mode, docKey);
42+
if (mode === 'mypastes') {
43+
postFileToRegistry(result.skylink, docKey, url);
44+
var docID = retrievalString + docKey;
45+
var docFound = false;
46+
for (let i = 0; i < myPastes.documents.length; i++) {
47+
if (myPastes.documents[i].docID == docID) {
48+
docLabel = myPastes.documents[i].label;
49+
docFound = true;
50+
}
51+
};
52+
docLabel = docLabel || prompt("Add a label to this document. Only you can see this label.");
53+
if (!docFound) {
54+
updateMyPastes(docID);
55+
}
56+
} else {
57+
window.location = url.url;
58+
showCopyBar(url.content);
59+
}
60+
})
61+
.catch((error) => {
62+
console.error(error);
63+
});
64+
};
65+
66+
export const buildUrl = (retrievalString, mode, docKey) => {
67+
const base =
68+
`${location.protocol}//${location.host}${location.pathname}`;
69+
const lang = shorten("Plain Text") === select.selected() ? "" :
70+
`.${encodeURIComponent(select.selected())}`;
71+
const url = base + "#" + retrievalString + docKey + lang;
72+
if (mode === "iframe") {
73+
const height = editor.doc.height + 45;
74+
let content =
75+
`<iframe width="100%" height="${height}" frameborder="0" src="${url}"></iframe>`;
76+
return {
77+
url: url,
78+
content: content
79+
};
80+
}
81+
return {
82+
url: url,
83+
content: url
84+
};
85+
};
86+
87+
export const generateEmbed = () => generateLink('iframe');
88+
89+
export const generateSnapshotUrl = () => generateLink('url');
90+
91+
export const generatePersistentUrl = () => generateLink('mypastes');
92+
93+
async function postFileToRegistry(skylink, docKey, url) {
94+
skyid.setRegistry(`hackerpaste:file:${docKey}`, skylink, (success) => {
95+
if (success !== false) {
96+
window.location = url.url;
97+
showCopyBar(url.content);
98+
skyid.hideOverlay(skyid.opts);
99+
}
100+
});
101+
}

‎src/randomString.js ‎src/utility.js

+63-78
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,66 @@
1-
// Source: https://gist.githubusercontent.com/dchest/751fd00ee417c947c252/raw/53c4e953b4748f4a46367fc1bce4aee8cfc4a1cb/randomString.js
2-
//
3-
// randomString(length)
4-
// --------------------
5-
//
6-
// Generates and returns a cryptographically secure
7-
// uniform alphanumeric random string.
8-
//
9-
// Examples:
10-
//
11-
// randomString(14) // "oXYWpc1vODNR3M"
12-
// randomString.hex(8) // "663c722b65943b9b"
13-
// randomString.entropy(128) // "Ss9waKhjUqOpcoOYgz8zx5"
14-
// randomString.hex.entropy(64) // "132ae4800cae9418"
15-
//
16-
// If length is 0 or omitted, returns a string containing
17-
// 128 bits of entropy, which is good enough for most
18-
// purposes (i.e. globally unique and unpredictable).
19-
//
20-
// randomString() // "shTJbSVWxm4sgqVZiZornN"
21-
// randomString.hex() // "2658a04afc409f15ce3527545a88b722"
22-
// randomString.base64() // "ttlfbFR5dFn+Fp3TrYWd+D"
23-
//
24-
// randomString.entropy(bits)
25-
// returns a random string containing at least
26-
// the given number of bits of entropy
27-
//
28-
// randomString.charset
29-
// (read-only) gets charset used to generate strings
30-
//
31-
// Functions for different charsets
32-
// (each have the corresponding .entropy and .charset properties):
33-
//
34-
// randomString.alphanumeric(length)
35-
// alias for randomString, range: [A-Z, a-z, 0-9]
36-
//
37-
// randomString.alpha(length)
38-
// returns a random alphabetic string in [A-Z, a-z]
39-
//
40-
// randomString.alphalower(length)
41-
// returns a random lowercase alphabetic string in [a-z]
42-
//
43-
// randomString.hex(length)
44-
// returns a random hex string in [0-9, a-f]
45-
//
46-
// randomString.numeric(length)
47-
// returns a random numeric string in [0-9]
48-
//
49-
// randomString.base64(length)
50-
// returns an unpadded random Base64 string in [A-Z, a-z, 0-9, +, /]
51-
//
52-
// randomString.url(length)
53-
// returns an unpadded random URL-safe Base64 string in [A-Z, a-z, 0-9, -, _]
54-
//
55-
// randomString.custom(charset)
56-
// returns a function which generates random strings
57-
// with characters from the given charset string:
58-
//
59-
// var randomAbc = randomString.custom('abc')
60-
// randomAbc(10) // "bccccccaac"
61-
// randomAbc.entropy(32) // "aabccbabccaaabcacaacb"
62-
// randomAbc.charset // "abc"
63-
//
64-
// Testing:
65-
//
66-
// randomString.test(quick)
67-
// runs a self-test and throws if there are errors.
68-
// If quick is true, skips some long tests.
69-
//
70-
// ---
71-
// Made by Dmitry Chestnykh (@dchest) in 2016.
72-
// Public domain.
73-
// ---
74-
(function() {
1+
/*jshint esversion: 8 */
2+
3+
const slugify = (str) =>
4+
str
5+
.trim()
6+
.toString()
7+
.toLowerCase()
8+
.replace(/\s+/g, "-")
9+
.replace(/\+/g, "-p")
10+
.replace(/#/g, "-sharp")
11+
.replace(/[^\w\-]+/g, "");
12+
13+
export const shorten = (name) => {
14+
let n = slugify(name).replace("script", "-s").replace("python", "py");
15+
const nov = (s) => s[0] + s.substr(1).replace(/[aeiouy-]/g, "");
16+
if (n.replace(/-/g, "").length <= 4) {
17+
return n.replace(/-/g, "");
18+
}
19+
if (n.split("-").length >= 2) {
20+
return n
21+
.split("-")
22+
.map((x) => nov(x.substr(0, 2)))
23+
.join("")
24+
.substr(0, 4);
25+
}
26+
n = nov(n);
27+
if (n.length <= 4) {
28+
return n;
29+
}
30+
return n.substr(0, 2) + n.substr(n.length - 2, 2);
31+
};
32+
33+
// https://gist.github.com/GeorgioWan/16a7ad2a255e8d5c7ed1aca3ab4aacec
34+
const hexToBase64 = (str) => {
35+
return btoa(String.fromCharCode.apply(null,
36+
str.replace(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ")
37+
.replace(/ +$/, "").split(" "))).replace('+', '-').replace('/', '_');
38+
};
39+
40+
// https://gist.github.com/GeorgioWan/16a7ad2a255e8d5c7ed1aca3ab4aacec
41+
export const base64ToHex = (str) => {
42+
for (var i = 0, bin = atob(str.replace(/[ \r\n]+$/, "").replace('-',
43+
'+')
44+
.replace('_', '/')), hex = []; i < bin
45+
.length; ++i) {
46+
let tmp = bin.charCodeAt(i).toString(16);
47+
if (tmp.length === 1) tmp = "0" + tmp;
48+
hex[hex.length] = tmp;
49+
}
50+
return hex.join("");
51+
};
52+
53+
export const generateDocKey = () => generateRandomString.url(20);
54+
55+
export const generateUuid = () => generateRandomString.alphanumeric(16);
56+
57+
export const getPubkeyBasedRetrievalString = (pubkey) =>
58+
hexToBase64(pubkey + '00');
59+
60+
// Source:
61+
// https://gist.githubusercontent.com/dchest/751fd00ee417c947c252/raw/53c4e953b4748f4a46367fc1bce4aee8cfc4a1cb/randomString.js
62+
63+
var generateRandomString = (function() {
7564

7665
var getRandomBytes = (
7766
(typeof self !== 'undefined' && (self.crypto || self.msCrypto))
@@ -217,10 +206,6 @@
217206
}
218207
};
219208

220-
if (typeof module !== 'undefined' && module.exports) {
221-
module.exports = randomString;
222-
}
223-
224209
return randomString;
225210

226211
}());

0 commit comments

Comments
 (0)
Please sign in to comment.