diff --git a/README.md b/README.md index fbc6358..e665fd4 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,11 @@ ![](https://i.imgur.com/AHHWH3z.png) -# Tytanium +## Tytanium -A durable and secure private file host solution. Intended for personal or small group use. - -## Features +Tytanium is a private file host program, meant for a single user or a small group. Here are the main highlights: +- SHA-512 file encryption at rest, with an encryption key unique to each file - Tune the server to exactly how you want with extensive customization options -- Built with [fasthttp](https://github.com/vayala/fasthttp) for optimal performance instead of the native http module -- File whitelist/blacklist type checks done via file headers rather than extensions -- Sanitize file type from rendering in HTML/other types to mitigate phishing attacks (Change their Content-Type to text/plain) -- Option to return a zero-width file IDs in a URL after upload - paste invisible but functional links! - Works well with image capture suites, such as ShareX/MagicCap - Good on system resources (<1MiB memory usage when idle) - Limit how many requests/second to certain paths to prevent DoS attacks or an overloaded server @@ -20,15 +15,13 @@ A durable and secure private file host solution. Intended for personal or small 1. Download the binary in the Releases tab, or build the code from source. 2. Rename `example.yml` to `config.yml` and set the values you want, or create a `config.yml` from scratch. -3. Start the binary with your method of choice. -4. Done! +3. Mark the binary as executable (this can be done with `chmod`). -### How to Use +### How to Upload 1. Create a POST request to `/upload` with a file in the field "file". Put the key in the `Authorization` header. 2. Set `?omitdomain=1`, if you don't want the host's original domain appended before the file name in the response. For example: `a.png` instead of `https://a.com/a.png`. This is useful if you have vanity/proxy domains you want to use. -3. Add `?zerowidth=1` and set it to `1` to make your image URLs appear "zero-width". If you don't get what that means, try it, and see what happens. -4. The server will respond with a link to the file (or just the file name if you set `?omitdomain=1`). It will be just text so no need to parse any JSON. +3. The server will respond with JSON with fields `uri` and `encryption_key`. `uri` will be just the file name if `?omitdomain=1` was specified. ### Optional stuff diff --git a/api/configuration.go b/api/configuration.go index b2abf84..5924855 100644 --- a/api/configuration.go +++ b/api/configuration.go @@ -13,6 +13,7 @@ type Configuration struct { StatsCollectionInterval int Logging loggingConfig Encryption encryptionConfig + Domain string } type encryptionConfig struct { diff --git a/conf/example.yml b/conf/example.yml index 9531173..e65dc74 100644 --- a/conf/example.yml +++ b/conf/example.yml @@ -108,3 +108,19 @@ Logging: # Configure logging behavior. # If logging is enabled, where should logs be written to? (Default is "log.txt" file in the project dir) LogFile: + +Encryption: # Configure encryption behavior. + # The length of the encryption key that is used in the query string (enc_key) when decoding files. + # Try not to make it too long or URLs will be abnormally long. + # By default, the length is 12. + EncryptionKeyLength: + + # The string which helps in creating the encryption key for files. + # You don't have to keep it private, and it can be any string. + # Keep in mind that if you change this, files previously encrypted using this nonce will be impossible to decrypt. + Nonce: + +# The URL from which this server will be accessible from, for example, https://example.com. +# If you have multiple proxy domains, pick one of them to use here; +# it doesn't matter as long as it connects to the server. +Domain: \ No newline at end of file diff --git a/constants/constants.go b/constants/constants.go index 473138a..f8d0498 100644 --- a/constants/constants.go +++ b/constants/constants.go @@ -23,7 +23,7 @@ const ( const ( RateLimitBandwidthDownload = "bw_dn_" - RateLimitBandwidthUpload = "bw_up_" + RateLimitBandwidthUpload = "bw_up_" ) const ( diff --git a/go.mod b/go.mod index a0ff7e9..5406b65 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/vysiondev/tytanium +module tytanium go 1.17 @@ -17,6 +17,7 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/klauspost/compress v1.15.0 // indirect github.com/magiconair/properties v1.8.5 // indirect + github.com/minio/sio v0.3.0 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/pelletier/go-toml v1.9.3 // indirect github.com/spf13/afero v1.6.0 // indirect @@ -25,6 +26,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect + golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect golang.org/x/text v0.3.7 // indirect diff --git a/go.sum b/go.sum index b440b0c..316f569 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Xeoncross/go-aesctr-with-hmac v0.0.0-20200623134604-12b17a7ff502 h1:L8IbaI/W6h5Cwgh0n4zGeZpVK78r/jBf9ASurHo9+/o= +github.com/Xeoncross/go-aesctr-with-hmac v0.0.0-20200623134604-12b17a7ff502/go.mod h1:pmnBM9bxWSiHvC/gSWunUIyDvGn33EkP2CUjxFKtTTM= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -195,6 +197,8 @@ github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/minio/sio v0.3.0 h1:syEFBewzOMOYVzSTFpp1MqpSZk8rUNbz8VIIc+PNzus= +github.com/minio/sio v0.3.0/go.mod h1:8b0yPp2avGThviy/+OCJBI6OMpvxoUuiLvE6F1lebhw= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= @@ -284,10 +288,12 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -441,6 +447,7 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/utils/zws.go b/utils/zws.go deleted file mode 100644 index 8b50264..0000000 --- a/utils/zws.go +++ /dev/null @@ -1,72 +0,0 @@ -package utils - -import ( - "strings" -) - -// hey yeah if it works and its stupid it aint stupid -const characterIndex = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789." - -var ( - characterReference = []string{ - "\U000E0050", "\U000E0043", "\U000E0034", "\U000E0035", - "\U000E002D", "\U000E002A", "\U000E005D", "\U000E002E", - "\U000E0026", "\U000E0024", "\U000E0058", "\U000E004E", - "\U000E0037", "\U000E0049", "\U000E0051", "\U000E0041", - "\U000E0028", "\U000E0027", "\U000E004B", "\U000E005E", - "\U000E0044", "\U000E0040", "\U000E004D", "\U000E0056", - "\U000E0060", "\U000E0055", "\U000E0030", "\U000E0023", - "\U000E0039", "\U000E004F", "\U000E0052", "\U000E002B", - "\U000E0057", "\U000E003C", "\U000E0053", "\U000E005B", - "\U000E003F", "\U000E0021", "\U000E003B", "\U000E0046", - "\U000E0031", "\U000E0059", "\U000E003E", "\U000E0047", - "\U000E005C", "\U000E003D", "\U000E0054", "\U000E0048", - "\U000E005F", "\U000E0038", "\U000E003A", "\U000E002F", - "\U000E005A", "\U000E0020", "\U000E0042", "\U000E0033", - "\U000E0036", "\U000E004A", "\U000E0022", "\U000E0045", - "\U000E0032", "\U000E002C", "\U000E0029", - } -) - -func GetCharacterIndex(s string) int { - return strings.Index(characterIndex, s) -} - -func ZeroWidthCharactersToString(baseStr string) string { - - var completedStr string - - for i := 0; i < len(baseStr); i++ { - r := characterReference[GetCharacterIndex(string(baseStr[i]))] - if len(r) == 0 { - // means we're trying to create a string without a character in the reference - return "" - } - completedStr += r - } - - return completedStr -} - -// what else am i supposed to call it dumbass -func StringToZeroWidthCharacters(encodedStr string) string { - - rL := []rune(encodedStr) - var finalStr string - - for _, r := range rL { - match := false - for i, v := range characterReference { - if []rune(v)[0] == r { - match = true - finalStr += string(characterIndex[i]) - break - } - } - if !match { - return "" - } - } - - return finalStr -}