├── .placeholder ├── .envrc ├── client ├── favicon │ ├── 128px.png │ ├── 16px.png │ ├── 32px.png │ └── 64px.png ├── config.js.example ├── deps │ ├── hybrid.min.css │ ├── sjcl.min.js │ ├── zepto.min.js │ └── highlight.min.js ├── js │ ├── shims.js │ ├── textpaste.js │ ├── loadencryption.js │ ├── updown.js │ ├── dragresize.js │ ├── encryption.js │ ├── main.js │ ├── home.js │ └── download.js ├── index.html └── css │ └── up1.css ├── .gitignore ├── server.json.example ├── README.md ├── flake.nix ├── Cargo.toml ├── flake.lock ├── src └── main.rs └── Cargo.lock /.placeholder: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | -------------------------------------------------------------------------------- /client/favicon/128px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upload/up1-rust/master/client/favicon/128px.png -------------------------------------------------------------------------------- /client/favicon/16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upload/up1-rust/master/client/favicon/16px.png -------------------------------------------------------------------------------- /client/favicon/32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upload/up1-rust/master/client/favicon/32px.png -------------------------------------------------------------------------------- /client/favicon/64px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upload/up1-rust/master/client/favicon/64px.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | 3 | .direnv 4 | result 5 | 6 | debug/ 7 | target/ 8 | 9 | client/config.js 10 | server.json 11 | i/ 12 | -------------------------------------------------------------------------------- /server.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "listen": "0.0.0.0:5000", 3 | 4 | "images": "../up1/i", 5 | "client": "../up1/client", 6 | 7 | "api_key": "c61540b5ceecd05092799f936e27755f", 8 | "delete_key": "madness" 9 | } 10 | -------------------------------------------------------------------------------- /client/config.js.example: -------------------------------------------------------------------------------- 1 | upload.config.server = '' // Empty if the webapp is in the same place as the server 2 | // upload.config.server = 'https://yourserver.com/' // If the webapp is separated from the server - remember the trailing slash 3 | upload.config.api_key = 'c61540b5ceecd05092799f936e27755f' // Should be the same as the server, used for uploading 4 | upload.config.footer = 'Source Code - Contact' 5 | -------------------------------------------------------------------------------- /client/deps/hybrid.min.css: -------------------------------------------------------------------------------- 1 | .hljs{display:block;overflow-x:auto;padding:0.5em;background:#1d1f21}.hljs{color:#c5c8c6}.hljs-title,.hljs-name{color:#f0c674}.hljs-comment,.hljs-meta,.hljs-meta .hljs-keyword{color:#707880}.hljs-number,.hljs-symbol,.hljs-literal,.hljs-deletion,.hljs-link{color:#c66}.hljs-string,.hljs-doctag,.hljs-addition,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo{color:#b5bd68}.hljs-attribute,.hljs-code,.hljs-selector-id{color:#b294bb}.hljs-keyword,.hljs-selector-tag,.hljs-bullet,.hljs-tag{color:#81a2be}.hljs-subst,.hljs-variable,.hljs-template-tag,.hljs-template-variable{color:#8abeb7}.hljs-type,.hljs-built_in,.hljs-builtin-name,.hljs-quote,.hljs-section,.hljs-selector-class{color:#de935f}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold} 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![Logo](https://avatars2.githubusercontent.com/u/12774718?s=150) 3 | 4 | # Up1: A Client-side Encrypted Image Host 5 | 6 | Up1 is a simple host that client-side encrypts images, text, and other data, and stores them, with the server knowing nothing about the contents. 7 | It has the ability to view images, text with syntax highlighting, short videos, and arbitrary binaries as downloadables. 8 | 9 | 10 | # Rust 11 | 12 | This is the Rust server implementation of Up1. For more information about Up1 in general, visit https://github.com/Upload/Up1. 13 | 14 | 15 | # Usage 16 | 17 | After cloning this repo, there are two ways to run this: 18 | 19 | ## Rustup 20 | 21 | Install rustup from https://rustup.rs/, then run: 22 | 23 | ``` 24 | cargo run --release 25 | ``` 26 | 27 | ## Nix 28 | 29 | Install nix from https://github.com/DeterminateSystems/nix-installer, then run: 30 | 31 | ``` 32 | nix run 33 | ``` 34 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | 2 | { 3 | inputs = { 4 | naersk.url = "github:nix-community/naersk/master"; 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 6 | utils.url = "github:numtide/flake-utils"; 7 | }; 8 | 9 | outputs = { self, nixpkgs, utils, naersk }: 10 | utils.lib.eachDefaultSystem (system: 11 | let 12 | pkgs = import nixpkgs { inherit system; }; 13 | naersk-lib = pkgs.callPackage naersk { }; 14 | in 15 | { 16 | defaultPackage = naersk-lib.buildPackage ./.; 17 | devShell = with pkgs; mkShell { 18 | buildInputs = [ 19 | cargo 20 | cargo-outdated 21 | rustc 22 | rustfmt 23 | pre-commit 24 | rustPackages.clippy 25 | rust-analyzer 26 | pkg-config 27 | ]; 28 | RUST_SRC_PATH = rustPlatform.rustLibSrc; 29 | }; 30 | } 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "up1-rust" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | axum = { version = "0.7.5", features = ["multipart", "http2"] } 10 | camino = { version = "1.0.7", features = ["serde1"] } 11 | clap = { version = "4.5.4", features = ["derive"] } 12 | config-file = { version = "0.2.3", features = ["json"], default-features = false } 13 | hex = "0.4.3" 14 | hmac-sha256 = "1.1.2" 15 | serde = { version = "1.0.137", features = ["serde_derive", "derive"] } 16 | tempfile = "3.3.0" 17 | tokio = { version = "1.18.1", features = ["rt", "rt-multi-thread", "tokio-macros", "macros", "sync", "parking_lot", "fs"] } 18 | tower-http = { version = "0.5.2", features = ["fs", "trace"] } 19 | tracing = "0.1.34" 20 | tracing-subscriber = { version = "0.3.11", features = ["std", "env-filter"] } 21 | anyhow = "1.0.57" 22 | thiserror = "1.0.31" 23 | mime = "0.3.17" 24 | -------------------------------------------------------------------------------- /client/js/shims.js: -------------------------------------------------------------------------------- 1 | if (typeof String.prototype.startsWith != 'function') { 2 | String.prototype.startsWith = function (str) { 3 | return this.slice(0, str.length) == str 4 | } 5 | } 6 | 7 | function dataURItoBlob(dataURI) { 8 | // convert base64 to raw binary data held in a string 9 | // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this 10 | var byteString = atob(dataURI.split(',')[1]); 11 | 12 | // separate out the mime component 13 | var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0] 14 | 15 | // write the bytes of the string to an ArrayBuffer 16 | var ab = new ArrayBuffer(byteString.length); 17 | var ia = new Uint8Array(ab); 18 | for (var i = 0; i < byteString.length; i++) { 19 | ia[i] = byteString.charCodeAt(i); 20 | } 21 | 22 | // write the ArrayBuffer to a blob, and you're done 23 | return new Blob([ab], { type: mimeString }); 24 | } 25 | 26 | function isiframed() { 27 | try { 28 | return window.self !== window.top; 29 | } catch (e) { 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Up1 11 | 12 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /client/js/textpaste.js: -------------------------------------------------------------------------------- 1 | upload.modules.addmodule({ 2 | name: 'textpaste', 3 | init: function () { 4 | $(document).on('submit', '#textview', this.save.bind(this)) 5 | $(document).on('click', '#retbtn', this.closethis.bind(this)) 6 | $(document).on('keydown', this.keypress.bind(this)) 7 | }, 8 | keypress: function(e) { 9 | if (!this.current) { 10 | return 11 | } 12 | 13 | if (!(e.which == 83 && (e.ctrlKey || e.metaKey))) { 14 | return 15 | } 16 | 17 | this.save() 18 | e.preventDefault() 19 | }, 20 | save: function(e) { 21 | e ? e.preventDefault() : undefined 22 | var blob = new Blob([this.current.find('textarea').val()], 23 | { 24 | type: this.current.find('#create_mime').val() 25 | } 26 | ) 27 | blob.name = this.current.find('#create_filename').val() 28 | window.location = '#noref' 29 | upload.route.setroute(upload.home) 30 | upload.home.doupload(blob) 31 | }, 32 | cleanup: function() { 33 | delete this['closeback'] 34 | delete this['current'] 35 | }, 36 | closethis: function() { 37 | var closeback = this.closeback 38 | this.current.remove() 39 | this.cleanup() 40 | closeback() 41 | }, 42 | render: function(view, filename, data, mime, closeback) { 43 | var main = $('
').prop('id', 'textview').prop('autocomplete', 'off') 44 | 45 | main.appendTo(view) 46 | 47 | this.closeback = closeback 48 | this.current = main 49 | 50 | main.append($('
').addClass('topbar').append($('
').addClass('viewswitcher').append( 51 | $('