').prop('id', 'create_linenos').append(">"))
66 | .append(area)
67 |
68 | main.append(text)
69 |
70 |
71 | area.val(data).focus()[0].setSelectionRange(0, 0)
72 |
73 | area.scrollTop(0)
74 | }
75 | })
76 |
--------------------------------------------------------------------------------
/flake.lock:
--------------------------------------------------------------------------------
1 | {
2 | "nodes": {
3 | "naersk": {
4 | "inputs": {
5 | "nixpkgs": "nixpkgs"
6 | },
7 | "locked": {
8 | "lastModified": 1698420672,
9 | "narHash": "sha256-/TdeHMPRjjdJub7p7+w55vyABrsJlt5QkznPYy55vKA=",
10 | "owner": "nix-community",
11 | "repo": "naersk",
12 | "rev": "aeb58d5e8faead8980a807c840232697982d47b9",
13 | "type": "github"
14 | },
15 | "original": {
16 | "owner": "nix-community",
17 | "ref": "master",
18 | "repo": "naersk",
19 | "type": "github"
20 | }
21 | },
22 | "nixpkgs": {
23 | "locked": {
24 | "lastModified": 0,
25 | "narHash": "sha256-WKm9CvgCldeIVvRz87iOMi8CFVB1apJlkUT4GGvA0iM=",
26 | "path": "/nix/store/yy5l09gfsagkv8rswblknmsjc2gyr20d-source",
27 | "type": "path"
28 | },
29 | "original": {
30 | "id": "nixpkgs",
31 | "type": "indirect"
32 | }
33 | },
34 | "nixpkgs_2": {
35 | "locked": {
36 | "lastModified": 1713254108,
37 | "narHash": "sha256-0TZIsfDbHG5zibtlw6x0yOp3jkInIGaJ35B7Y4G8Pec=",
38 | "owner": "NixOS",
39 | "repo": "nixpkgs",
40 | "rev": "2fd19c8be2551a61c1ddc3d9f86d748f4db94f00",
41 | "type": "github"
42 | },
43 | "original": {
44 | "owner": "NixOS",
45 | "ref": "nixpkgs-unstable",
46 | "repo": "nixpkgs",
47 | "type": "github"
48 | }
49 | },
50 | "root": {
51 | "inputs": {
52 | "naersk": "naersk",
53 | "nixpkgs": "nixpkgs_2",
54 | "utils": "utils"
55 | }
56 | },
57 | "systems": {
58 | "locked": {
59 | "lastModified": 1681028828,
60 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
61 | "owner": "nix-systems",
62 | "repo": "default",
63 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
64 | "type": "github"
65 | },
66 | "original": {
67 | "owner": "nix-systems",
68 | "repo": "default",
69 | "type": "github"
70 | }
71 | },
72 | "utils": {
73 | "inputs": {
74 | "systems": "systems"
75 | },
76 | "locked": {
77 | "lastModified": 1710146030,
78 | "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
79 | "owner": "numtide",
80 | "repo": "flake-utils",
81 | "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
82 | "type": "github"
83 | },
84 | "original": {
85 | "owner": "numtide",
86 | "repo": "flake-utils",
87 | "type": "github"
88 | }
89 | }
90 | },
91 | "root": "root",
92 | "version": 7
93 | }
94 |
--------------------------------------------------------------------------------
/client/js/loadencryption.js:
--------------------------------------------------------------------------------
1 | window.crypt = {}
2 |
3 | var crypto = window.crypto || window.msCrypto;
4 |
5 | function getEntropy() {
6 | var entropy = new Uint32Array(256)
7 | crypto.getRandomValues(entropy)
8 | return entropy
9 | }
10 |
11 | function getSeed() {
12 | var seed = new Uint8Array(16)
13 | crypto.getRandomValues(seed)
14 | return seed
15 | }
16 |
17 | var worker = new Worker("./js/encryption.js")
18 |
19 |
20 | var promises = {}
21 |
22 | function str2ab(str) {
23 | var buf = new ArrayBuffer(str.length * 2);
24 | var bufView = new DataView(buf);
25 | for (var i = 0, strLen = str.length; i < strLen; i++) {
26 | bufView.setUint16(i * 2, str.charCodeAt(i), false)
27 | }
28 | return buf;
29 | }
30 |
31 | worker.onmessage = function (e) {
32 | if (e.data.type == 'progress') {
33 | promises[e.data.id].notify(e.data)
34 | } else {
35 | promises[e.data.id].resolve(e.data)
36 | delete promises[e.data.id]
37 | }
38 | }
39 |
40 | var counter = 0
41 |
42 | function getpromise() {
43 | var promise = $.Deferred()
44 | var promiseid = counter
45 | counter += 1
46 | promise.id = promiseid
47 | promises[promiseid] = promise;
48 | return promise
49 | }
50 |
51 | crypt.encrypt = function (file, name) {
52 |
53 | var extension = file.type.split('/')
54 |
55 | var header = JSON.stringify({
56 | 'mime': file.type,
57 | 'name': name ? name : (file.name ? file.name : ('Pasted ' + extension[0] + '.' + (extension[1] == 'plain' ? 'txt' : extension[1])))
58 | })
59 |
60 | var zero = new Uint8Array([0, 0]);
61 |
62 | var blob = new Blob([str2ab(header), zero, file])
63 |
64 | var promise = getpromise()
65 |
66 | var fr = new FileReader()
67 |
68 | fr.onload = function () {
69 | worker.postMessage({
70 | 'data': this.result,
71 | 'entropy': getEntropy(),
72 | 'seed': getSeed(),
73 | 'id': promise.id
74 | })
75 | }
76 |
77 | fr.readAsArrayBuffer(blob)
78 |
79 | return promise
80 | }
81 |
82 |
83 | crypt.ident = function (seed) {
84 | var promise = getpromise()
85 |
86 | worker.postMessage({
87 | 'seed': seed,
88 | 'action': 'ident',
89 | 'id': promise.id
90 | })
91 |
92 | return promise
93 | }
94 |
95 |
96 | crypt.decrypt = function (file, seed) {
97 | var promise = getpromise()
98 |
99 | var fr = new FileReader()
100 |
101 | fr.onload = function () {
102 | worker.postMessage({
103 | 'data': this.result,
104 | 'action': 'decrypt',
105 | 'seed': seed,
106 | 'id': promise.id
107 | })
108 | }
109 |
110 | fr.readAsArrayBuffer(file)
111 |
112 | return promise
113 | }
114 |
--------------------------------------------------------------------------------
/client/js/updown.js:
--------------------------------------------------------------------------------
1 | upload.modules.addmodule({
2 | name: 'updown',
3 | init: function () {
4 | // We do this to try to hide the fragment from the referral in IE
5 | this.requestframe = document.createElement('iframe')
6 | this.requestframe.src = 'about:blank'
7 | this.requestframe.style.visibility = 'hidden'
8 | document.body.appendChild(this.requestframe)
9 | },
10 | downloadfromident: function(seed, progress, done, ident) {
11 | var xhr = new this.requestframe.contentWindow.XMLHttpRequest()
12 | xhr.onload = this.downloaded.bind(this, seed, progress, done)
13 | xhr.open('GET', (upload.config.server ? upload.config.server : '') + 'i/' + ident.ident)
14 | xhr.responseType = 'blob'
15 | xhr.onerror = this.onerror.bind(this, progress)
16 | xhr.addEventListener('progress', progress, false)
17 | xhr.send()
18 | },
19 | onerror: function(progress) {
20 | progress('error')
21 | },
22 | downloaded: function (seed, progress, done, response) {
23 | if (response.target.status != 200) {
24 | this.onerror(progress)
25 | } else {
26 | this.cache(seed, response.target.response)
27 | progress('decrypting')
28 | crypt.decrypt(response.target.response, seed).done(done)
29 | }
30 | },
31 | encrypted: function(progress, done, data) {
32 | var formdata = new FormData()
33 | formdata.append('api_key', upload.config.api_key)
34 | formdata.append('ident', data.ident)
35 | formdata.append('file', data.encrypted)
36 | $.ajax({
37 | url: (upload.config.server ? upload.config.server : '') + 'up',
38 | data: formdata,
39 | cache: false,
40 | processData: false,
41 | contentType: false,
42 | dataType: 'json',
43 | xhr: function () {
44 | var xhr = new XMLHttpRequest()
45 | xhr.upload.addEventListener('progress', progress, false)
46 | return xhr
47 | },
48 | type: 'POST'
49 | }).done(done.bind(undefined, data))
50 | },
51 | cache: function(seed, data) {
52 | this.cached = data
53 | this.cached_seed = seed
54 | },
55 | cacheresult: function(data) {
56 | this.cache(data.seed, data.encrypted)
57 | },
58 | download: function (seed, progress, done) {
59 | if (this.cached_seed == seed) {
60 | progress('decrypting')
61 | crypt.decrypt(this.cached, seed).done(done).progress(progress)
62 | } else {
63 | crypt.ident(seed).done(this.downloadfromident.bind(this, seed, progress, done))
64 | }
65 | },
66 | upload: function (blob, progress, done) {
67 | crypt.encrypt(blob).done(this.encrypted.bind(this, progress, done)).done(this.cacheresult.bind(this)).progress(progress)
68 | }
69 | })
70 |
--------------------------------------------------------------------------------
/client/js/dragresize.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 | window.dragresize = true
3 |
4 | var dragging
5 |
6 | var lastx
7 | var lasty
8 |
9 | var dragsizew
10 | var dragsizeh
11 |
12 | var minw
13 | var minh
14 |
15 | var maxw
16 | var maxh
17 |
18 | $(document).on('dblclick', '.dragresize', function (e) {
19 | var target = $(e.target)
20 | target.toggleClass('full')
21 | if (target.hasClass('full')) {
22 | target.addClass('dragged')
23 | target.width(e.target.naturalWidth)
24 | target.height(e.target.naturalHeight)
25 | } else {
26 | target.removeClass('dragged')
27 | target.width('auto')
28 | target.height('auto')
29 | }
30 | })
31 |
32 | var MIN_WIDTH_PX = 100
33 | var MAX_WIDTH_RATIO = 100
34 |
35 | $(document).on('mousedown', '.dragresize', function (e) {
36 | if (e.which && e.which != 1) {
37 | return
38 | }
39 | e.preventDefault();
40 | dragging = $(e.target)
41 | dragging.addClass('dragging')
42 | dragsizew = e.target.naturalWidth
43 | dragsizeh = e.target.naturalHeight
44 |
45 | if (dragsizew > dragsizeh) {
46 | minw = MIN_WIDTH_PX
47 | minh = MIN_WIDTH_PX * (dragsizeh / dragsizew)
48 | maxw = dragsizew * MAX_WIDTH_RATIO
49 | maxh = (dragsizew * MAX_WIDTH_RATIO) * (dragsizeh / dragsizew)
50 | } else {
51 | minh = MIN_WIDTH_PX
52 | minw = MIN_WIDTH_PX * (dragsizew / dragsizeh)
53 | maxh = dragsizeh * MAX_WIDTH_RATIO
54 | maxw = (dragsizeh * MAX_WIDTH_RATIO) * (dragsizew / dragsizeh)
55 | }
56 |
57 | lastx = e.clientX
58 | lasty = e.clientY
59 | })
60 |
61 | $(document).on('mousemove', function (e) {
62 | if (!dragging) {
63 | return
64 | }
65 |
66 | var px = e.clientX
67 | var py = e.clientY
68 |
69 | var newx = px - lastx
70 | var newy = py - lasty
71 |
72 | if (Math.abs(newx) < 1 && Math.abs(newy) < 1) {
73 | return;
74 | }
75 |
76 | e.preventDefault();
77 |
78 | var width = dragging.width()
79 | var height = dragging.height()
80 |
81 | dragging.addClass('dragged')
82 |
83 | if (Math.abs(newx) > Math.abs(newy)) {
84 | dragging.css({ 'width': Math.min(maxw, Math.max(width + (width * (.0025 * newx)), minw)) + 'px', 'height': 'auto' })
85 | } else {
86 | dragging.css({ 'height': Math.min(maxh, Math.max(height + (height * (.0025 * newy)), minh)) + 'px', 'width': 'auto' })
87 | }
88 |
89 |
90 | lastx = px
91 | lasty = py
92 |
93 | })
94 |
95 | $(document).on('mouseup', function (e) {
96 | if (!dragging) {
97 | return
98 | }
99 | dragging.removeClass('dragging')
100 | dragging = undefined
101 | });
102 | })
103 |
--------------------------------------------------------------------------------
/client/js/encryption.js:
--------------------------------------------------------------------------------
1 | importScripts('../deps/sjcl.min.js')
2 |
3 | function parametersfrombits(seed) {
4 | var out = sjcl.hash.sha512.hash(seed)
5 | return {
6 | 'seed': seed,
7 | 'key': sjcl.bitArray.bitSlice(out, 0, 256),
8 | 'iv': sjcl.bitArray.bitSlice(out, 256, 384),
9 | 'ident': sjcl.bitArray.bitSlice(out, 384, 512)
10 | }
11 | }
12 |
13 | function parameters(seed) {
14 | if (typeof seed == 'string') {
15 | seed = sjcl.codec.base64url.toBits(seed)
16 | } else {
17 | seed = sjcl.codec.bytes.toBits(seed)
18 | }
19 | return parametersfrombits(seed)
20 | }
21 |
22 | function encrypt(file, seed, id) {
23 | var params = parameters(seed)
24 | var uarr = new Uint8Array(file)
25 | var before = sjcl.codec.bytes.toBits(uarr)
26 | var prp = new sjcl.cipher.aes(params.key)
27 | var after = sjcl.mode.ccm.encrypt(prp, before, params.iv)
28 | var afterarray = new Uint8Array(sjcl.codec.bytes.fromBits(after))
29 | postMessage({
30 | 'id': id,
31 | 'seed': sjcl.codec.base64url.fromBits(params.seed),
32 | 'ident': sjcl.codec.base64url.fromBits(params.ident),
33 | 'encrypted': new Blob([afterarray], { type: 'application/octet-stream' })
34 | })
35 | }
36 |
37 | var fileheader = [
38 | 85, 80, 49, 0
39 | ]
40 |
41 | function decrypt(file, seed, id) {
42 | var params = parameters(seed)
43 | var uarr = new Uint8Array(file)
44 |
45 | // We support the servers jamming a header in to deter direct linking
46 | var hasheader = true
47 | for (var i = 0; i < fileheader.length; i++) {
48 | if (uarr[i] != fileheader[i]) {
49 | hasheader = false
50 | break
51 | }
52 | }
53 | if (hasheader) {
54 | uarr = uarr.subarray(fileheader.length)
55 | }
56 |
57 | var before = sjcl.codec.bytes.toBits(uarr);
58 | var prp = new sjcl.cipher.aes(params.key);
59 | var after = sjcl.mode.ccm.decrypt(prp, before, params.iv);
60 | var afterarray = new Uint8Array(sjcl.codec.bytes.fromBits(after));
61 |
62 | // Parse the header, which is a null-terminated UTF-16 string containing JSON
63 | var header = ''
64 | var headerview = new DataView(afterarray.buffer)
65 | var i = 0;
66 | for (; ; i++) {
67 | var num = headerview.getUint16(i * 2, false)
68 | if (num == 0) {
69 | break;
70 | }
71 | header += String.fromCharCode(num);
72 | }
73 | var header = JSON.parse(header)
74 |
75 | var data = new Blob([afterarray])
76 | postMessage({
77 | 'id': id,
78 | 'ident': sjcl.codec.base64url.fromBits(params.ident),
79 | 'header': header,
80 | 'decrypted': data.slice((i * 2) + 2, data.size, header.mime)
81 | })
82 | }
83 |
84 | function ident(seed, id) {
85 | var params = parameters(seed)
86 | postMessage({
87 | 'id': id,
88 | 'ident': sjcl.codec.base64url.fromBits(params.ident)
89 | })
90 | }
91 |
92 | function onprogress(id, progress) {
93 | postMessage({
94 | 'id': id,
95 | 'eventsource': 'encrypt',
96 | 'loaded': progress,
97 | 'total': 1,
98 | 'type': 'progress'
99 | })
100 | }
101 |
102 | onmessage = function (e) {
103 | var progress = onprogress.bind(undefined, e.data.id)
104 | sjcl.mode.ccm.listenProgress(progress)
105 | if (e.data.action == 'decrypt') {
106 | decrypt(e.data.data, e.data.seed, e.data.id)
107 | } else if (e.data.action == 'ident') {
108 | ident(e.data.seed, e.data.id)
109 | } else {
110 | sjcl.random.addEntropy(e.data.entropy, 2048, 'runtime')
111 | encrypt(e.data.data, e.data.seed, e.data.id)
112 | }
113 | sjcl.mode.ccm.unListenProgress(progress)
114 | }
115 |
--------------------------------------------------------------------------------
/client/js/main.js:
--------------------------------------------------------------------------------
1 | (function(window) {
2 | "use strict";
3 | window.upload = {}
4 | }(window));
5 |
6 |
7 | (function(upload) {
8 | upload.config = {}
9 |
10 | upload.load = {
11 | loaded: 0,
12 | doneloaded: function() {
13 | this.loaded -= 1
14 | if (this.loaded <= 0) {
15 | this.cb()
16 | }
17 | },
18 | load: function(filename, test, onload) {
19 | if (test && test()) {
20 | return false
21 | }
22 | var head = document.getElementsByTagName('head')[0]
23 | var script = document.createElement('script')
24 | script.src = './' + filename
25 | script.async = true
26 | script.onload = onload
27 | head.appendChild(script)
28 | return true
29 | },
30 | needsome: function() {
31 | this.loaded += 1
32 | return this
33 | },
34 | done: function(callback) {
35 | this.loaded -= 1
36 | this.cb = callback
37 | return this
38 | },
39 | then: function(callback) {
40 | this.deferred.then(callback)
41 | return this
42 | },
43 | need: function(filename, test) {
44 | this.loaded += 1
45 | if(!this.load(filename, test, this.doneloaded.bind(this))) {
46 | this.loaded -= 1
47 | }
48 | return this
49 | }
50 | }
51 |
52 | upload.modules = {
53 | modules: [],
54 | addmodule: function (module) {
55 | this.modules.unshift(module)
56 | upload[module.name] = module
57 | },
58 | initmodule: function (module) {
59 | module.init()
60 | },
61 | setdefault: function (module) {
62 | this.default = module
63 | },
64 | init: function () {
65 | this.modules.forEach(this.initmodule.bind(this))
66 | }
67 | }
68 |
69 | upload.modules.addmodule({
70 | name: 'footer',
71 | init: function() {
72 | $('#footer').html(upload.config.footer)
73 | }
74 | })
75 |
76 | upload.modules.addmodule({
77 | name: 'route',
78 | init: function () {
79 | window.addEventListener('hashchange', this.hashchange.bind(this))
80 | this.hashchange()
81 | },
82 | setroute: function (module, routeroot, route) {
83 | view = $('.modulecontent.modulearea')
84 | if (!this.currentmodule || this.currentmodule != module) {
85 | // TODO: better
86 | if (this.currentmodule) {
87 | this.currentmodule.unrender()
88 | }
89 | this.currentmodule = module
90 | view.id = 'module_' + module.name
91 | module.render(view)
92 | }
93 | module.initroute(route, routeroot)
94 | },
95 | tryroute: function (route) {
96 | var isroot = route.startsWith('/')
97 | var normalroute = isroot ? route.substring(1) : route
98 | var route = normalroute.substr(normalroute.indexOf('/') + 1)
99 | var routeroot = normalroute.substr(0, normalroute.indexOf('/'))
100 | var chosenmodule
101 | if (!normalroute) {
102 | chosenmodule = upload.modules.default
103 | } else {
104 | upload.modules.modules.every(function (module) {
105 | if (!module.route) {
106 | return true
107 | }
108 | if (module.route(routeroot, route)) {
109 | chosenmodule = module
110 | return false
111 | }
112 | return true
113 | })
114 | }
115 | if (!chosenmodule) {
116 | chosenmodule = upload.modules.default
117 | }
118 | setTimeout(this.setroute.bind(this, chosenmodule, routeroot, route), 0)
119 | },
120 | hashchange: function () {
121 | this.tryroute(window.location.hash.substring(1))
122 | }
123 | })
124 | }(window.upload));
125 |
126 |
127 | (function () {
128 | upload.load.needsome().need('config.js').need('js/shims.js').need('deps/zepto.min.js').done(function() {
129 | upload.load.needsome().need('js/home.js', function() {return upload.home}).done(function() {
130 | if (typeof upload.config != 'undefined') {
131 | upload.modules.init()
132 | } else {
133 | alert("Please configure with config.js (see config.js.example)")
134 | }
135 | })
136 | })
137 | }(upload))
138 |
--------------------------------------------------------------------------------
/client/css/up1.css:
--------------------------------------------------------------------------------
1 | #btnarea {
2 | bottom: 5px;
3 | position: fixed;
4 | z-index: 1;
5 | width: 100%;
6 | }
7 |
8 | #btnarea .right {
9 | margin-right: 5px;
10 | }
11 |
12 | #create_filename {
13 | background-color: rgba(0,0,0,.5);
14 | border: 1px solid #FFF;
15 | border-bottom-right-radius: initial;
16 | box-sizing: border-box;
17 | color: #FFF;
18 | font-size: 16px;
19 | left: 10px;
20 | margin: 0;
21 | max-width: 100%;
22 | opacity: .75;
23 | overflow: hidden;
24 | padding: 5px;
25 | position: fixed;
26 | top: 10px;
27 | white-space: nowrap;
28 | width: 170px;
29 | z-index: 1;
30 | }
31 |
32 | #downloaded_filename {
33 | background-color: rgba(0,0,0,.5);
34 | border-radius: 5px;
35 | box-sizing: border-box;
36 | color: #FFF;
37 | display: block;
38 | height: 40px;
39 | line-height: 30px;
40 | margin: 0;
41 | opacity: .75;
42 | overflow: hidden;
43 | padding: 5px;
44 | text-align: middle;
45 | text-overflow: ellipsis;
46 | vertical-align: middle;
47 | white-space: nowrap;
48 | z-index: 1;
49 | }
50 |
51 | #finallink,#downloadprogress {
52 | color: #FFF;
53 | }
54 |
55 | #create_linenos {
56 | color: #7d7d7d;
57 | float: left;
58 | font-family: monospace;
59 | left: 5px;
60 | overflow: hidden;
61 | position: absolute;
62 | text-align: right;
63 | top: 6.5px;
64 | width: 30px;
65 | z-index: -1;
66 | }
67 |
68 | .line {
69 | word-wrap: normal;
70 | white-space: pre-wrap;
71 | min-height: 1em;
72 | }
73 |
74 | .line:after {
75 | content: "";
76 | }
77 |
78 | .line .linenum {
79 | -webkit-user-select: none; /* Chrome all / Safari all */
80 | -moz-user-select: none; /* Firefox all */
81 | -ms-user-select: none; /* IE 10+ */
82 | user-select: none; /* Likely future */
83 | color: #7d7d7d;
84 | font-family: monospace;
85 | padding: 0 15px 0 10px;
86 | text-align: center;
87 | position: absolute;
88 | left: -8px;
89 | text-align: right;
90 | width: 30px;
91 | }
92 |
93 | #module_download .preview {
94 | display: block;
95 | margin: 0 auto;
96 | max-height: 100%;
97 | max-width: 100%;
98 | }
99 |
100 | #module_download,#downloaddetails {
101 | height: 100%;
102 | position: absolute;
103 | top: 0;
104 | width: 100%;
105 | }
106 |
107 | #pastearea {
108 | cursor: pointer;
109 | }
110 |
111 | #pastearea.dragover {
112 | background-color: rgba(255,255,255,.2);
113 | }
114 |
115 | #pastearea:hover {
116 | -moz-transition: background-color 100ms ease-in;
117 | -ms-transition: background-color 100ms ease-in;
118 | -o-transition: background-color 100ms ease-in;
119 | -webkit-transition: background-color 100ms ease-in;
120 | background-color: #313538;
121 | transition: background-color 100ms ease-in;
122 | }
123 |
124 | #pastecatcher {
125 | height: 0;
126 | left: 0;
127 | opacity: 0;
128 | overflow: hidden;
129 | position: absolute;
130 | top: 0;
131 | width: 0;
132 | }
133 |
134 | #previewimg {
135 | max-height: 100%;
136 | max-width: 100%;
137 | }
138 |
139 | #previewimg img, .preview video, .preview audio {
140 | display: block;
141 | margin: 0 auto;
142 | }
143 |
144 | #previewimg img:not(.dragged), .preview audio, .preview video {
145 | max-height: 100vh;
146 | max-width: 100vw;
147 | }
148 |
149 | #progressamountbg {
150 | background-color: rgba(0,10,0,.5);
151 | height: 100%;
152 | left: 0;
153 | position: absolute;
154 | top: 0;
155 | width: 0;
156 | z-index: -1;
157 | }
158 |
159 | #uploadview .centerview {
160 | display: table;
161 | height: 100%;
162 | width: 100%;
163 | }
164 |
165 | .boxarea {
166 | -moz-transition: background-color 400ms ease-out;
167 | -ms-transition: background-color 400ms ease-out;
168 | -o-transition: background-color 400ms ease-out;
169 | -webkit-transition: background-color 400ms ease-out;
170 | transition: background-color 400ms ease-out;
171 | }
172 |
173 | .btn {
174 | -webkit-box-align: start;
175 | background-color: rgba(0,0,0,.5);
176 | border: 2px solid #FFF;
177 | box-sizing: border-box;
178 | color: #FFF!important;
179 | cursor: pointer;
180 | display: inline-block;
181 | font: inherit;
182 | font-size: 16px;
183 | height: 40px;
184 | line-height: 16px;
185 | margin: 0 0 0 5px;
186 | opacity: .75;
187 | padding: 10px;
188 | text-align: center;
189 | text-decoration: none;
190 | transition: all 400ms ease-out;
191 | vertical-align: middle;
192 | white-space: nowrap;
193 | }
194 |
195 | .btn:hover {
196 | background-color: #313538;
197 | opacity: 1;
198 | transition: all 100ms ease-in;
199 | }
200 |
201 | .contentarea {
202 | border: 2px solid #FFF;
203 | bottom: 0;
204 | color: #FFF;
205 | height: 200px;
206 | left: 0;
207 | margin: auto;
208 | position: absolute;
209 | right: 0;
210 | text-align: center;
211 | top: 0;
212 | vertical-align: middle;
213 | width: 200px;
214 | }
215 |
216 | .contentarea .boxarea {
217 | display: table-cell;
218 | text-align: center;
219 | vertical-align: middle;
220 | }
221 |
222 | .contentarea h1 {
223 | margin: 0;
224 | }
225 |
226 | .downloadexplain {
227 | color: #fff;
228 | font-size: 30px;
229 | }
230 |
231 | .dragresize.dragging {
232 | cursor: nwse-resize;
233 | }
234 |
235 | .footer {
236 | bottom: 10px;
237 | margin: auto;
238 | position: fixed;
239 | text-align: center;
240 | width: 100%;
241 | color: #FFF;
242 | }
243 |
244 | .footer a {
245 | color: #FFF;
246 | font-size: 14px;
247 | opacity: .5;
248 | text-decoration: none;
249 | }
250 |
251 | .hidden {
252 | display: none!important;
253 | }
254 |
255 | .loadingtext {
256 | color: #FFF;
257 | text-align: center;
258 | }
259 |
260 | .noscript {
261 | color: #FFF;
262 | margin: 0;
263 | text-align: center;
264 | vertical-align: middle;
265 | }
266 |
267 | .previewtext {
268 | height: calc(100% - 110px);
269 | overflow: auto;
270 | position: absolute;
271 | top: 55px;
272 | width: 100%;
273 | }
274 |
275 | .previewtext > textarea {
276 | background: transparent none repeat scroll 0 0;
277 | border: 0 none;
278 | box-sizing: border-box;
279 | color: #c5c8c6!important;
280 | font-family: monospace!important;
281 | font-size: 13px;
282 | height: calc(100% - 5px);
283 | margin: 0;
284 | outline: medium none;
285 | padding: 6.5px 0 0 50px;
286 | position: absolute;
287 | resize: none;
288 | width: 100%;
289 | }
290 |
291 | .previewtext code {
292 | background: none;
293 | margin: 0;
294 | overflow: visible;
295 | }
296 |
297 | .previewtext pre {
298 | margin: 0;
299 |
300 | padding-left: 50px;
301 | }
302 |
303 | .topbar {
304 | box-sizing: border-box;
305 | display: flex;
306 | height: 40px;
307 | padding: 5px;
308 | position: fixed;
309 | width: 100%;
310 | z-index: 1;
311 | }
312 |
313 | .viewcontent {
314 | height: 100%;
315 | width: 100%;
316 | }
317 |
318 | .viewswitcher {
319 | -webkit-flex-shrink: 0;
320 | display: flex;
321 | flex-shrink: 0;
322 | margin-left: auto;
323 | vertical-align: top;
324 | white-space: nowrap;
325 | }
326 |
327 | .centertext {
328 | text-align: center;
329 | }
330 |
331 | .centerable {
332 | -webkit-transform: translateY(-50%);
333 | margin: 0 auto;
334 | position: relative;
335 | top: 50%;
336 | transform: translateY(-50%);
337 | }
338 |
339 | body {
340 | background-color: #1d1f21;
341 | overflow: auto;
342 | }
343 |
344 | body,html {
345 | font-family: Sans-Serif;
346 | height: 100%;
347 | margin: 0;
348 | overflow: auto;
349 | padding: 0;
350 | }
351 |
352 | .right {
353 | float: right;
354 | }
355 |
--------------------------------------------------------------------------------
/client/js/home.js:
--------------------------------------------------------------------------------
1 | upload.load.need('js/download.js', function() { return upload.download })
2 | upload.load.need('js/textpaste.js', function() { return upload.textpaste })
3 | upload.load.need('js/loadencryption.js', function() { return window.crypt })
4 | upload.load.need('js/updown.js', function() { return upload.updown })
5 |
6 | upload.modules.addmodule({
7 | name: 'home',
8 | // Dear santa, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings
9 | template: '\
10 |
\
15 |
\
16 |
\
17 |
\
18 |
Upload
\
19 | \
20 |
\
21 |
\
22 |
\
23 |
\
24 |
\
25 |
\
28 |
\
31 |
\
32 |
',
33 | init: function () {
34 | upload.modules.setdefault(this)
35 | $(document).on('change', '#filepicker', this.pickerchange.bind(this))
36 | $(document).on('click', '#pastearea', this.pickfile.bind(this))
37 | $(document).on('dragover', '#pastearea', this.dragover.bind(this))
38 | $(document).on('dragleave', '#pastearea', this.dragleave.bind(this))
39 | $(document).on('drop', '#pastearea', this.drop.bind(this))
40 | $(document).on('click', '#newpaste', this.newpaste.bind(this))
41 | $(document).on('click', this.triggerfocuspaste.bind(this))
42 | this.initpastecatcher()
43 | $(document).on('paste', this.pasted.bind(this))
44 | },
45 | dragleave: function (e) {
46 | e.preventDefault()
47 | e.stopPropagation()
48 | this._.pastearea.removeClass('dragover')
49 | },
50 | drop: function (e) {
51 | e.preventDefault()
52 | this._.pastearea.removeClass('dragover')
53 | if (e.dataTransfer.files.length > 0) {
54 | this.doupload(e.dataTransfer.files[0])
55 | }
56 | },
57 | dragover: function (e) {
58 | e.preventDefault()
59 | this._.pastearea.addClass('dragover')
60 | },
61 | pickfile: function(e) {
62 | this._.filepicker.click()
63 | },
64 | pickerchange: function(e) {
65 | if (e.target.files.length > 0) {
66 | this.doupload(e.target.files[0])
67 | $(e.target).parents('form')[0].reset()
68 | }
69 | },
70 | route: function (route, content) {
71 | if (content && content != 'noref') {
72 | return upload.download
73 | }
74 | return this
75 | },
76 | render: function (view) {
77 | view.html(this.template)
78 | this._ = {}
79 | this._.view = view
80 | this._.filepicker = view.find('#filepicker')
81 | this._.pastearea = view.find('#pastearea')
82 | this._.newpaste = view.find('#newpaste')
83 | this._.progress = {}
84 | this._.progress.main = view.find('#uploadprogress')
85 | this._.progress.type = view.find('#progresstype')
86 | this._.progress.amount = view.find('#progressamount')
87 | this._.progress.bg = view.find('#progressamountbg')
88 | $('#footer').show()
89 | },
90 | initroute: function () {
91 | this.focuspaste()
92 | },
93 | unrender: function() {
94 | delete this['_']
95 | },
96 | initpastecatcher: function () {
97 | this.pastecatcher = $('
').prop('id', 'pastecatcher')
98 | this.pastecatcher.prop('contenteditable', true)
99 | $('body').append(this.pastecatcher)
100 | },
101 | focuspaste: function () {
102 | setTimeout(function () {
103 | this.pastecatcher.focus()
104 | }, 100)
105 | },
106 | triggerfocuspaste: function(e) {
107 | if (e.which != 1) {
108 | return
109 | }
110 |
111 | if (e.target == document.body && this._ && !this._.pastearea.hasClass('hidden')) {
112 | e.preventDefault()
113 | this.focuspaste()
114 | }
115 | },
116 | progress: function(e) {
117 | if (e.eventsource != 'encrypt') {
118 | this._.progress.type.text('Uploading')
119 | } else {
120 | this._.progress.type.text('Encrypting')
121 | }
122 | var percent = (e.loaded / e.total) * 100
123 | this._.progress.bg.css('width', percent + '%')
124 | this._.progress.amount.text(Math.floor(percent) + '%')
125 | },
126 | doupload: function (blob) {
127 | this._.pastearea.addClass('hidden')
128 | this._.progress.main.removeClass('hidden')
129 | this._.progress.type.text('Encrypting')
130 | this._.progress.bg.css('width', 0)
131 | this._.newpaste.addClass('hidden')
132 | upload.updown.upload(blob, this.progress.bind(this), this.uploaded.bind(this))
133 | },
134 | closepaste: function() {
135 | this._.pastearea.removeClass('hidden')
136 | this._.view.find('#uploadview').show()
137 | this._.view.find('.viewswitcher').show()
138 | },
139 | dopasteupload: function (data) {
140 | this._.pastearea.addClass('hidden')
141 | this._.view.find('#uploadview').hide()
142 | this._.view.find('.viewswitcher').hide()
143 | upload.textpaste.render(this._.view, 'Pasted text.txt', data, 'text/plain', this.closepaste.bind(this))
144 | },
145 | uploaded: function (data, response) {
146 | upload.download.delkeys[data.ident] = response.delkey
147 |
148 | try {
149 | localStorage.setItem('delete-' + data.ident, response.delkey)
150 | } catch (e) {
151 | console.log(e)
152 | }
153 |
154 | if (window.location.hash == '#noref') {
155 | history.replaceState(undefined, undefined, '#' + data.seed)
156 | upload.route.setroute(upload.download, undefined, data.seed)
157 | } else {
158 | window.location = '#' + data.seed
159 | }
160 | },
161 | newpaste: function() {
162 | this.dopasteupload('')
163 | },
164 | pasted: function (e) {
165 | if (!this._ || this._.pastearea.hasClass('hidden')) {
166 | return
167 | }
168 |
169 | var items = e.clipboardData.items
170 |
171 | var text = e.clipboardData.getData('text/plain')
172 |
173 | if (text) {
174 | e.preventDefault()
175 | this.dopasteupload(text)
176 | } else if (typeof items == 'undefined') {
177 | self = this
178 | setTimeout(function () {
179 | if (self.pastecatcher.find('img').length) {
180 | var src = self.pastecatcher.find('img').prop('src')
181 | if (src.startsWith('data:')) {
182 | self.doupload(dataURItoBlob(src))
183 | } else {
184 | // TODO: Firefox
185 | }
186 | }
187 | }, 0)
188 | } else if (items.length >= 1) {
189 | e.preventDefault()
190 |
191 | for (var i = 0; i < items.length; i++) {
192 | var blob = items[i].getAsFile()
193 | if (blob) {
194 | this.doupload(blob)
195 | break
196 | }
197 | }
198 |
199 | }
200 | },
201 | })
202 |
--------------------------------------------------------------------------------
/client/js/download.js:
--------------------------------------------------------------------------------
1 | upload.load.need('js/dragresize.js', function() { return window.dragresize })
2 |
3 | upload.modules.addmodule({
4 | name: 'download',
5 | delkeys: {},
6 | // Dear santa, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings
7 | template: '\
8 | \
9 |
\
16 |
\
17 |
\
24 |
\
25 | ',
26 | init: function () {
27 | $(document).on('click', '#editpaste', this.editpaste.bind(this))
28 | },
29 | route: function (route, content) {
30 | if (content != 'noref') {
31 | return this
32 | }
33 | },
34 | render: function (view) {
35 | view.html(this.template)
36 | this._ = {}
37 | this._.view = view
38 | this._.detailsarea = view.find('#downloaddetails')
39 | this._.filename = view.find('#downloaded_filename')
40 | this._.btns = view.find('#btnarea')
41 | this._.deletebtn = view.find('#deletebtn')
42 | this._.dlbtn = view.find('#dlbtn')
43 | this._.nextbtn = view.find('#nextbtn')
44 | this._.prevbtn = view.find('#prevbtn')
45 | this._.viewbtn = view.find('#inbrowserbtn')
46 | this._.viewswitcher = view.find('.viewswitcher')
47 | this._.newupload = view.find('#newupload')
48 | this._.editpaste = view.find('#editpaste')
49 | this._.dlarea = view.find('#dlarea')
50 | this._.title = $('title')
51 | $('#footer').hide()
52 | },
53 | initroute: function (content, contentroot) {
54 | contentroot = contentroot ? contentroot : content
55 | this._.nextbtn.hide()
56 | this._.prevbtn.hide()
57 | if (contentroot.indexOf('&') > -1) {
58 | var which = 0
59 | var values = contentroot.split('&')
60 | var howmany = values.length
61 | if (content != contentroot) {
62 | which = parseInt(content) - 1
63 | }
64 | content = values[which]
65 | this._.nextbtn.attr('href', '#' + contentroot + '/' + (which + 2))
66 | this._.prevbtn.attr('href', '#' + contentroot + '/' + (which))
67 | if (!(which >= howmany - 1)) {
68 | this._.nextbtn.show()
69 | }
70 | if (!(which <= 0)) {
71 | this._.prevbtn.show()
72 | }
73 | }
74 | console.log(contentroot)
75 | delete this._['text']
76 | this._.filename.hide()
77 | this._.title.text("Up1")
78 | this._.btns.hide()
79 | this._.editpaste.hide()
80 | this._.newupload.hide()
81 | this._.content = {}
82 | this._.content.main = this._.content.loading = $('