From b8f3169f57febf0e1fc4cb6f572896595e279925 Mon Sep 17 00:00:00 2001 From: Dominika Date: Sat, 23 May 2020 22:13:11 +0200 Subject: [PATCH] Initial commit, importing from tarball --- LICENSE.md | 157 ++++ README.md | 49 ++ config/localhost | 1 + config/master.sh | 20 + http.sh | 24 + secret/users.dat | 1 + src/account.sh | 81 ++ src/mime.sh | 28 + src/misc.sh | 19 + src/response/101.sh | 31 + src/response/200.sh | 16 + src/response/401.sh | 3 + src/response/403.sh | 4 + src/response/404.sh | 4 + src/response/listing.sh | 33 + src/server.sh | 174 ++++ src/ws.sh | 69 ++ storage/faves | 1 + storage/pastes | 0 templates/head.sh | 36 + webroot/allegro/index.shs | 8 + webroot/allegro/listing.shs | 68 ++ webroot/allegro/listing_bottom.txt | 820 +++++++++++++++++ webroot/allegro/listing_top.txt | 1321 ++++++++++++++++++++++++++++ webroot/boards/i/empty | 0 webroot/boards/index.shs | 34 + webroot/boards/post.shs | 48 + webroot/boards/style.css | 42 + webroot/boards/thread.shs | 46 + webroot/img/branding_chinacat.png | Bin 0 -> 7701 bytes webroot/img/branding_pxplus.png | Bin 0 -> 4641 bytes webroot/index.shs | 65 ++ webroot/login.shs | 30 + webroot/logout.shs | 7 + webroot/pastebin/index.shs | 56 ++ webroot/pastebin/list | 0 webroot/register.shs | 25 + webroot/shortener/index.shs | 35 + webroot/upload/index.shs | 18 + webroot/yt/fav.shs | 19 + webroot/yt/index.shs | 16 + webroot/yt/search.shs | 34 + webroot/yt/unfav.shs | 10 + webroot/yt/watch.shs | 59 ++ 44 files changed, 3512 insertions(+) create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 config/localhost create mode 100644 config/master.sh create mode 100755 http.sh create mode 100644 secret/users.dat create mode 100755 src/account.sh create mode 100755 src/mime.sh create mode 100755 src/misc.sh create mode 100755 src/response/101.sh create mode 100755 src/response/200.sh create mode 100755 src/response/401.sh create mode 100755 src/response/403.sh create mode 100755 src/response/404.sh create mode 100755 src/response/listing.sh create mode 100755 src/server.sh create mode 100755 src/ws.sh create mode 100644 storage/faves create mode 100644 storage/pastes create mode 100755 templates/head.sh create mode 100644 webroot/allegro/index.shs create mode 100755 webroot/allegro/listing.shs create mode 100644 webroot/allegro/listing_bottom.txt create mode 100644 webroot/allegro/listing_top.txt create mode 100644 webroot/boards/i/empty create mode 100644 webroot/boards/index.shs create mode 100644 webroot/boards/post.shs create mode 100644 webroot/boards/style.css create mode 100644 webroot/boards/thread.shs create mode 100644 webroot/img/branding_chinacat.png create mode 100644 webroot/img/branding_pxplus.png create mode 100644 webroot/index.shs create mode 100755 webroot/login.shs create mode 100755 webroot/logout.shs create mode 100755 webroot/pastebin/index.shs create mode 100644 webroot/pastebin/list create mode 100755 webroot/register.shs create mode 100755 webroot/shortener/index.shs create mode 100755 webroot/upload/index.shs create mode 100644 webroot/yt/fav.shs create mode 100755 webroot/yt/index.shs create mode 100755 webroot/yt/search.shs create mode 100644 webroot/yt/unfav.shs create mode 100755 webroot/yt/watch.shs diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..0927556 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,157 @@ +### GNU LESSER GENERAL PUBLIC LICENSE + +Version 3, 29 June 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. + + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +This version of the GNU Lesser General Public License incorporates the +terms and conditions of version 3 of the GNU General Public License, +supplemented by the additional permissions listed below. + +#### 0. Additional Definitions. + +As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the +GNU General Public License. + +"The Library" refers to a covered work governed by this License, other +than an Application or a Combined Work as defined below. + +An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + +A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + +The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + +The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + +#### 1. Exception to Section 3 of the GNU GPL. + +You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + +#### 2. Conveying Modified Versions. + +If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + +- a) under this License, provided that you make a good faith effort + to ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or +- b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + +#### 3. Object Code Incorporating Material from Library Header Files. + +The object code form of an Application may incorporate material from a +header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + +- a) Give prominent notice with each copy of the object code that + the Library is used in it and that the Library and its use are + covered by this License. +- b) Accompany the object code with a copy of the GNU GPL and this + license document. + +#### 4. Combined Works. + +You may convey a Combined Work under terms of your choice that, taken +together, effectively do not restrict modification of the portions of +the Library contained in the Combined Work and reverse engineering for +debugging such modifications, if you also do each of the following: + +- a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. +- b) Accompany the Combined Work with a copy of the GNU GPL and this + license document. +- c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. +- d) Do one of the following: + - 0) Convey the Minimal Corresponding Source under the terms of + this License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + - 1) Use a suitable shared library mechanism for linking with + the Library. A suitable mechanism is one that (a) uses at run + time a copy of the Library already present on the user's + computer system, and (b) will operate properly with a modified + version of the Library that is interface-compatible with the + Linked Version. +- e) Provide Installation Information, but only if you would + otherwise be required to provide such information under section 6 + of the GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the Application + with a modified version of the Linked Version. (If you use option + 4d0, the Installation Information must accompany the Minimal + Corresponding Source and Corresponding Application Code. If you + use option 4d1, you must provide the Installation Information in + the manner specified by section 6 of the GNU GPL for conveying + Corresponding Source.) + +#### 5. Combined Libraries. + +You may place library facilities that are a work based on the Library +side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + +- a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities, conveyed under the terms of this License. +- b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + +#### 6. Revised Versions of the GNU Lesser General Public License. + +The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +as you received it specifies that a certain numbered version of the +GNU Lesser General Public License "or any later version" applies to +it, you have the option of following the terms and conditions either +of that published version or of any later version published by the +Free Software Foundation. If the Library as you received it does not +specify a version number of the GNU Lesser General Public License, you +may choose any version of the GNU Lesser General Public License ever +published by the Free Software Foundation. + +If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/README.md b/README.md new file mode 100644 index 0000000..239df1b --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# HTTP.sh +Node.js, but `| sed s/Node/HTTP/;s/js/sh/`. + +Launch with `./http.sh`. Does not need root priviliges ~~- in fact, DO NOT run it as superuser~~ unless you're running it on ports lower than 1024. If you're running on 80 and 443, superuser is more or less mandatory, but THIS MAY BE UNSAFE. + +To prevent running malicious scripts, by default only scripts with extension `.shs` can be run by the server, but this can be changed in the config. Also, cfg[index] ignores this. SHS stands for Shell Server. + +Originally made for Junction Stupidhack 2020; Created by @redsPL, @selfisekai and @ptrcnull. + +## Dependencies + +- Bash or 100% compatible shell +- [Ncat](https://nmap.org/ncat) +- pkill +- mktemp +- dd (for accounts, multipart/form-data and websockets) +- sha1sum, sha256sum (for accounts and simple auth) +- curl (for some demos) + +## Known faults + +- can't change the HTTP status code from Shell Server scripts. This could theoretically be done with custom vhost configs and some `if` statements, but this would be a rather nasty solution to that problem. +- `$post_multipart` doesn't keep original names - could be fixed by parsing individual headers from the multipart request instead of skipping them all + +## Directory structure (incomplete) +- config + - master.sh: main config file, loaded with every request + - localhost:1337: example vhost file, loaded if `Host: ...` equals its name +- src + - server source files and modules (e.g. `ws.sh`) + - response + - files corresponding to specific HTTP status codes + - listing.sh (code 210) is actually HTTP 200, but triggered in a directory with autoindex turned on and without a valid `index.shs` file +- templates + - section templates go here +- webroot + - place your files **here** +- secret + - users/passwords go here +- storage + - random data storage for shs apps + +## Variables that we think are cool! + +- $post_data - array, contains data from urlencoded POSTs +- $post_multipart - array, contains URIs to uploaded files from multipart/form-data POSTs +- $get_data - array, contains data from GETs +- $cfg - array, contains config values (from master.sh and vhost configs) +- $r - array, contains data generated from the request - URI, URL and that kinda stuff. diff --git a/config/localhost b/config/localhost new file mode 100644 index 0000000..9aa52e1 --- /dev/null +++ b/config/localhost @@ -0,0 +1 @@ +cfg[title]='Laura is cute :3' diff --git a/config/master.sh b/config/master.sh new file mode 100644 index 0000000..0d27f65 --- /dev/null +++ b/config/master.sh @@ -0,0 +1,20 @@ +declare -A cfg + +cfg[port]=1337 + +cfg[root]='webroot/' +cfg[index]='index.shs' +cfg[autoindex]=true + +cfg[auth_required]=false +cfg[auth_realm]="Laura is cute <3" + +cfg[ssl]=true +cfg[ssl_port]=8443 +cfg[ssl_cert]='' +cfg[ssl_key]='' + +cfg[extension]='shs' +cfg[extra_headers]='server: HTTP.sh/0.9' + +cfg[title]='ddd defies development' diff --git a/http.sh b/http.sh new file mode 100755 index 0000000..fad92f9 --- /dev/null +++ b/http.sh @@ -0,0 +1,24 @@ +#!/bin/bash +trap ctrl_c INT + +function ctrl_c() { + pkill -P $$ + echo -e "Killed all remaining processes.\nHave a great day!!" +} + +source config/master.sh +echo "HTTP.sh" + +if [[ ${cfg[ssl]} == true ]]; then + echo "listening on port ${cfg[port]} (HTTP) and ${cfg[ssl_port]} (HTTPS)" + ncat -l -p ${cfg[port]} -c ./src/server.sh -k & + if [[ ${cfg[ssl_key]} != '' && ${cfg[ssl_cert]} != '' ]]; then + ncat -l -p ${cfg[ssl_port]} -c ./src/server.sh -k --ssl --ssl-cert ${cfg[ssl_cert]} --ssl-key ${cfg[ssl_key]} + else + ncat -l -p ${cfg[ssl_port]} -c ./src/server.sh -k --ssl + fi +else + echo "listening on port ${cfg[port]} (HTTP)" + ncat -l -p ${cfg[port]} -c ./src/server.sh -k +fi + diff --git a/secret/users.dat b/secret/users.dat new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/secret/users.dat @@ -0,0 +1 @@ + diff --git a/src/account.sh b/src/account.sh new file mode 100755 index 0000000..e942d0b --- /dev/null +++ b/src/account.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# account.sh - account and session mgmt + + +# register(username, password) +function register() { + local username=$(echo -ne $(printf "$1" | sed -E "s/ /_/g;s/\:/\-/g;s/\%/\\x/g")) + + if [[ $(grep "$username:" secret/users.dat) != '' ]]; then + reason="This user already exists!" + return 1 + fi + + local salt=$(dd if=/dev/urandom bs=256 count=1 | sha1sum | cut -c 1-16) + local hash=$(echo -n $2$salt | sha256sum | cut -c 1-64) + local token=$(dd if=/dev/urandom bs=32 count=1 | sha1sum | cut -c 1-40) + set_cookie "sh_session" $token + set_cookie "username" $username + + echo "$username:$hash:$salt:$token" >> secret/users.dat +} + +# login(username, password) +function login() { + local username=$(echo -ne $(echo "$1" | sed -E 's/%/\\x/g')) + echo $1 $username > /dev/stderr + IFS=':' + local user=($(grep "$username:" secret/users.dat)) + unset IFS + if [[ $(echo -n $2${user[2]} | sha256sum | cut -c 1-64 ) == ${user[1]} ]]; then + set_cookie "sh_session" ${user[3]} + set_cookie "username" $username + return 0 + else + remove_cookie "sh_session" + remove_cookie "username" + reason="Invalid credentials!!11" + return 1 + fi +} + +# login_simple(base64) +function login_simple() { + local data=$(echo $3 | base64 -d) + echo $3 > /dev/stderr + local password=$(echo $data | sed -E 's/^(.*)\://') + local login=$(echo $data | sed -E 's/\:(.*)$//') + + IFS=':' + local user=($(grep "$login:" secret/users.dat)) + unset IFS + if [[ $(echo -n $password${user[2]} | sha256sum | cut -c 1-64 ) == ${user[1]} ]]; then + r[authorized]=true + echo "nay" > /dev/stderr + else + r[authorized]=false + fi +} + +# logout() +function logout() { + remove_cookie "sh_session" + remove_cookie "username" +} + +# session_verify(session) +function session_verify() { + if [[ $(grep ":$1" secret/users.dat) != '' && $1 != '' ]]; then + return 0 + else + return 1 + fi +} + +# session_get_username(session) +function session_get_username() { + IFS=':' + local data=($(grep ":$1" secret/users.dat)) + unset IFS + echo ${data[0]} +} diff --git a/src/mime.sh b/src/mime.sh new file mode 100755 index 0000000..e387bbe --- /dev/null +++ b/src/mime.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# mime.sh - determine what Content-Type should be passed on +# +# Common HTML files (.html/.htm) -> text/html +# Shell Server Scripts (.shs) -> leaves without any content type, TBD by the browser +# CSS files (.css) -> text/css +# Text files (mimetype starting with 'text/') -> text/plain (fixes XSS in pastebin) +# All else -> pass real mimetype + +function get_mime() { + local file=$@ + local mime=$(file --mime-type -b $file) + echo $file $mime > /dev/stderr + if [[ $file == *".htm" || $file == *".html" ]]; then + content_type="text/html" + return 0 + elif [[ $file == *".shs" ]]; then + content_type="" + return 0 + elif [[ $file == *".css" ]]; then + content_type="text/css" + elif [[ $mime == "text/"* ]]; then + content_type="text/plain" + else + content_type="$mime" + fi +} diff --git a/src/misc.sh b/src/misc.sh new file mode 100755 index 0000000..70bb4e5 --- /dev/null +++ b/src/misc.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# misc.sh - miscellaneous functions + +# set_cookie(cookie_name, cookie_content) +function set_cookie() { + r[headers]+="Set-Cookie: $1=$2\r\n" +} + +# remove_cookie(cookie_name) +function remove_cookie() { + r[headers]+="Set-Cookie: $1=; Expires=Sat, 02 Apr 2005 20:37:00 GMT\r\n" +} + +# header(header, header...) +function header() { + for i in "$@"; do + r[headers]+="$i\r\n" + done +} diff --git a/src/response/101.sh b/src/response/101.sh new file mode 100755 index 0000000..c3721c8 --- /dev/null +++ b/src/response/101.sh @@ -0,0 +1,31 @@ +echo "HTTP/1.1 101 Web Socket Protocol Handshake +Connection: Upgrade +Upgrade: WebSocket +${cfg[extra_headers]}" +if [[ ${r[websocket_key]} != '' ]]; then + accept=$(echo -ne $(printf "${r[websocket_key]}""258EAFA5-E914-47DA-95CA-C5AB0DC85B11" | sha1sum | sed 's/ //g;s/-//g;s/.\{2\}/\\x&/g') | base64) + echo "Sec-WebSocket-Accept: "$accept +fi +printf "\r\n\r\n" + +#echo "Laura is cute <3" +#WebSocket-Location: ws://localhost:1337/ +#WebSocket-Origin: http://localhost:1337/\r\n\r\n " + +source ./src/ws.sh + +#input='' +#while read -N 1 chr; do +# input=$input$chr +# if [[ $chr == "\r" ]]; then +# break +# fi +#done + + +exit 0 +#while true; do +# read test +# echo $test +# sleep 1 +#done diff --git a/src/response/200.sh b/src/response/200.sh new file mode 100755 index 0000000..60f5f78 --- /dev/null +++ b/src/response/200.sh @@ -0,0 +1,16 @@ +printf "HTTP/1.0 200 OK +${cfg[extra_headers]}\r\n" +get_mime ${r[uri]} +[[ $content_type != '' ]] && printf "content-type: $content_type\r\n" + +if [[ ${r[uri]} =~ \.${cfg[extension]}$ ]]; then + temp=$(mktemp) + source "${r[uri]}" > $temp + [[ ${r[headers]} != '' ]] && printf "${r[headers]}\r\n\r\n" || printf "\r\n" + cat $temp + rm $temp +else + printf "\r\n" + cat "${r[uri]}" +fi + diff --git a/src/response/401.sh b/src/response/401.sh new file mode 100755 index 0000000..e3bb213 --- /dev/null +++ b/src/response/401.sh @@ -0,0 +1,3 @@ +printf "HTTP/1.0 401 Unauthorized +WWW-Authenticate: Basic realm=\"${cfg[auth_realm]}\" +${cfg[extra_headers]}\r\n" diff --git a/src/response/403.sh b/src/response/403.sh new file mode 100755 index 0000000..44a2efb --- /dev/null +++ b/src/response/403.sh @@ -0,0 +1,4 @@ +printf "HTTP/1.0 403 Forbidden +${cfg[extra_headers]}\r\n\r\n" +source templates/head.sh +echo "

403: You've been naughty

" diff --git a/src/response/404.sh b/src/response/404.sh new file mode 100755 index 0000000..b60b500 --- /dev/null +++ b/src/response/404.sh @@ -0,0 +1,4 @@ +printf "HTTP/1.0 404 Not Found +${cfg[extra_headers]}\r\n\r\n" +source templates/head.sh +echo "

404 Not Found

" diff --git a/src/response/listing.sh b/src/response/listing.sh new file mode 100755 index 0000000..8fea773 --- /dev/null +++ b/src/response/listing.sh @@ -0,0 +1,33 @@ +printf "HTTP/1.0 200 OK +${cfg[extra_headers]}\r\n\r\n" + +source templates/head.sh + +printf "

Index of $([[ ${r[url]} == '' ]] && echo '/' || echo ${r[url]})

" + +if [[ ${cookies[username]} != '' ]]; then + echo "Logged in as ${cookies[username]}" +fi + +printf " + + + + + + + +" +IFS=$'\n' + +for i in $(ls ${r[uri]}); do + unset IFS + stats=($(ls -hld "${r[uri]}/$i")) # -hld stands for Half-Life Dedicated + if [[ -d ${r[uri]}'/'$i ]]; then + printf "" + else + printf "" + fi +done + +printf "
FileSizeDate
..
$i<DIR>${stats[5]} ${stats[6]} ${stats[7]}
$i${stats[4]}B${stats[5]} ${stats[6]} ${stats[7]}

HTTP.sh server on ${r[host]}

laura is cute

" diff --git a/src/server.sh b/src/server.sh new file mode 100755 index 0000000..4ed5c23 --- /dev/null +++ b/src/server.sh @@ -0,0 +1,174 @@ +#!/bin/bash +source config/master.sh +source src/mime.sh +source src/misc.sh +source src/account.sh + +declare -A r # current request / response +declare -A meta # metadata for templates +declare -A cookies # cookies! + +r[status]=210 # Mommy always said that I was special +post_length=0 +post=false +get=false + +while read param; do + if [[ $param == $'\015' ]]; then + break + + elif [[ $param == *"Content-Length:"* ]]; then + r[content_length]=$(echo -n $param | sed 's/Content-Length: //;s/\r//') + + elif [[ $param == *"Content-Type:"* ]]; then + r[content_type]=$(echo -n $param | sed 's/Content-Type: //;s/\r//') + if [[ ${r[content_type]} == *"multipart/form-data"* ]]; then + tmpdir=$(mktemp -d) + fi + if [[ ${r[content_type]} == *"boundary="* ]]; then + r[content_boundary]=$(echo -n ${r[content_type]} | sed -E 's/(.*)boundary=//;s/\r//;s/ //') + fi + + elif [[ $param == *"Host:"* ]]; then + r[host]=$(printf "$param" | sed 's/Host: //;s/\r//') + r[host_portless]=$(echo ${r[host]} | sed -E 's/:(.*)$//') + if [[ -f "config/${r[host]}" ]]; then + source "config/${r[host]}" + elif [[ -f "config/${r[host_portless]}" ]]; then + source "config/${r[host_portless]}" + fi + + elif [[ $param == *"Upgrade:"* && $(printf "$param" | sed 's/Upgrade: //;s/\r//') == "websocket" ]]; then + r[status]=101 + + elif [[ $param == *"Sec-WebSocket-Key:"* ]]; then + r[websocket_key]=$(printf "$param" | sed 's/Sec-WebSocket-Key: //;s/\r//') + + elif [[ $param == *"Authorization: Basic"* ]]; then + login_simple $param + + elif [[ $param == *"Cookie: "* ]]; then + for i in $(echo $param | sed -E 's/Cookie: //;s/\;//g;s/%/\\x/g'); do + name=$(echo $i | sed -E 's/\=(.*)$//') + value=$(echo $i | sed -E 's/^(.*)\=//') + cookies[$name]=$(echo -e $value) + done + + elif [[ $param == *"GET "* ]]; then + r[url]=$(echo -ne "$(echo -n $param | sed -E 's/GET //;s/HTTP\/[0-9]+\.[0-9]+//;s/ //g;s/\%/\\x/g;s/\/*\r//g;s/\/\/*/\//g')") + data=$(echo ${r[url]} | sed -E 's/^(.*)\?//;s/\&/ /g') + if [[ $data != ${r[url]} ]]; then + declare -A get_data + for i in $data; do + name=$(echo $i | sed -E 's/\=(.*)$//') + value=$(echo $i | sed "s/$name\=//") + get_data[$name]=$value + done + fi + + elif [[ $param == *"POST "* ]]; then + r[url]=$(echo -ne "$(echo -n $param | sed -E 's/POST //;s/HTTP\/[0-9]+\.[0-9]+//;s/ //g;s/\%/\\x/g;s/\/*\r//g;s/\/\/*/\//g')") + r[post]=true + # below shamelessly copied from GET, should be moved to a function + data=$(echo ${r[url]} | sed -E 's/^(.*)\?//;s/\&/ /g') + if [[ $data != ${r[url]} ]]; then + declare -A get_data + for i in $data; do + name=$(echo $i | sed -E 's/\=(.*)$//') + value=$(echo $i | sed "s/$name\=//") + get_data[$name]=$value + done + fi + + fi +done + +r[uri]=$(realpath ${cfg[root]}$(echo ${r[url]} | sed -E 's/\?(.*)$//')) +[[ -d "${r[uri]}/" ]] && pwd="${r[uri]}" || pwd=$(dirname "${r[uri]}") + +# shitty logging +echo "-------------" >> log +echo $(date) >> log +echo "URL: ${r[url]}, GET_data: ${get_data[@]}, POST_data: ${post_data[@]}, POST_multipart: ${post_multipart[@]}" >> log + +echo ${r[uri]} > /dev/stderr + +if [[ ${r[status]} != 101 ]]; then + if [[ -a ${r[uri]} && ! -r ${r[uri]} ]]; then + r[status]=403 + elif [[ "$(echo -n ${r[uri]})" != "$(realpath ${cfg[root]})"* ]]; then + r[status]=403 + elif [[ -f ${r[uri]} ]]; then + r[status]=200 + elif [[ -d ${r[uri]} ]]; then + for name in ${cfg[index]}; do + if [[ -f "${r[uri]}/$name" ]]; then + r[uri]="${r[uri]}/$name" + r[status]=200 + fi + done + else + r[status]=404 + fi +fi + +if [[ ${cfg[auth_required]} == true && ${r[authorized]} != true ]]; then + echo "Auth failed." >> log + r[status]=401 +fi + +if [[ ${r[post]} == true && ${r[status]} == 200 ]]; then + + # This whole ordeal is here to prevent passing binary data as a variable. + # I could have done it as an array, but this solution works, and it's + # speedy enough so I don't care. + + if [[ $tmpdir ]]; then + declare post_multipart + tmpfile=$(mktemp -p $tmpdir) + dd iflag=fullblock of=$tmpfile ibs=${r[content_length]} count=1 obs=1M + + delimeter_len=$(echo -n "$content_boundary"$'\015' | wc -c) + boundaries_list=$(echo -ne $(grep $tmpfile -ao -e ${r[content_boundary]} --byte-offset | sed -E 's/:(.*)//g') | sed -E 's/ [0-9]+$//') + + for i in $boundaries_list; do + tmpout=$(mktemp -p $tmpdir) + dd iflag=fullblock if=$tmpfile ibs=$(($i+$delimeter_len)) obs=1M skip=1 | while true; do + read line + if [[ $line == $'\015' ]]; then + cat - > $tmpout + break + fi + done + length=$(grep $tmpout --byte-offset -ae ${r[content_boundary]} | sed -E 's/:(.*)//' | head -n 1) + outfile=$(mktemp -p $tmpdir) + post_multipart+=($outfile) + dd iflag=fullblock if=$tmpout ibs=$length count=1 obs=1M of=$outfile + rm $tmpout + done + rm $tmpfile + else + read -N ${r[content_length]} data + declare -A post_data + + for i in $(echo $data | sed -s 's/\&/ /g;'); do + name=$(echo $i | sed -E 's/\=(.*)$//') + param=$(echo $i | sed "s/$name\=//") + post_data[$name]=$param + done + fi +fi + +if [[ ${r[status]} == 210 && ${cfg[autoindex]} == true ]]; then + source "src/response/listing.sh" +elif [[ ${r[status]} == 200 ]]; then + source "src/response/200.sh" +elif [[ ${r[status]} == 401 ]]; then + source "src/response/401.sh" +elif [[ ${r[status]} == 404 ]]; then + source "src/response/404.sh" +elif [[ ${r[status]} == 101 ]]; then + source "src/response/101.sh" +else + source "src/response/403.sh" +fi diff --git a/src/ws.sh b/src/ws.sh new file mode 100755 index 0000000..bd08867 --- /dev/null +++ b/src/ws.sh @@ -0,0 +1,69 @@ +#!/bin/zsh +read bytes + +echo "bytes:" > /dev/stderr +echo $bytes | hexdump -C > /dev/stderr + +readarray -t data <<< $(echo -n $bytes | hexdump -e '/1 "%u\n"') + +echo "data:" > /dev/stderr +echo ${data[@]} | hexdump -C > /dev/stderr + + +echo "FIN bit:" $(( ${data[0]} >> 7 )) > /dev/stderr + +echo "opcode:" $(( ${data[0]} & 0x0f )) > /dev/stderr + +echo ${data[0]} > /dev/stderr + +mask_bit=$(( ${data[1]} >> 7 )) +echo "Mask (bit):" $mask_bit > /dev/stderr + +len=$(( ${data[1]} & 0x7f )) +offset=2 # 2 for header + +if [[ $len == 126 ]]; then + len=$(( ${data[2]} << 8 + ${data[3]} )) + offset=4 # 2 for header, 2 for extended length +elif [[ $len == 127 ]]; then + len=0 + for i in {0..8}; do + len=$(( $len << 8 + ${data[2+i]} )) + done + offset=10 # 2 for header, 8 for extended length +fi + +echo "Data length:" $len > /dev/stderr + +echo "Offset:" $offset > /dev/stderr + +if [[ $mask_bit == 1 ]]; then + read -ra mask <<< ${data[@]:$offset:4} + + echo "Mask:" $mask > /dev/stderr + + offset=$(( $offset + 4 )) +fi + +read -ra payload <<< ${data[@]:$offset:$len} + +echo "Payload:" ${payload[@]} > /dev/stderr + +if [[ $mask_bit == 1 ]]; then + for ((i = 0; i < $len; i++)); do + byte=$(( ${payload[$i]} ^ ${mask[$i % 4]} )) + echo "Byte $i: $byte" > /dev/stderr + payload[$i]=$byte + done + + echo "Payload unmasked:" ${payload[@]} > /dev/stderr +fi + +payload_hex="" +for ((i = 0; i < $len; i++)); do + hex=$(printf '\\x%x\n' $(( ${payload[$i]} ))) + payload_hex+=$hex +done + +echo "Payload hex:" $payload_hex > /dev/stderr +echo -e "Payload: $payload_hex" > /dev/stderr diff --git a/storage/faves b/storage/faves new file mode 100644 index 0000000..7b71c6e --- /dev/null +++ b/storage/faves @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/storage/pastes b/storage/pastes new file mode 100644 index 0000000..e69de29 diff --git a/templates/head.sh b/templates/head.sh new file mode 100755 index 0000000..10271b7 --- /dev/null +++ b/templates/head.sh @@ -0,0 +1,36 @@ +#!/bin/bash +echo ' + + + ' + +if [[ ${meta[title]} ]]; then echo "${meta[title]} - ${cfg[title]}"; else echo "${cfg[title]}"; fi +if [[ ${meta[author]} ]]; then echo ""; fi +if [[ ${meta[description]} ]]; then echo ""; fi +if [[ ${meta[keywords]} ]]; then echo ""; fi +if [[ ${meta[refresh]} ]]; then echo ""; fi +if [[ ${meta[redirect]} ]]; then echo ""; fi +if [[ ${meta[css]} ]]; then echo ""; fi +if [[ ${meta[title]} ]]; then echo ""; fi +#if [[ ${meta[og:type]} ]]; then echo ""; fi +if [[ ${cfg[url]} ]]; then echo ""; fi +#if [[ ${meta[og:image} ]]; then echo ""; fi +if [[ ${meta[lang]} ]]; then echo ""; fi +if [[ ${meta[description]} ]]; then echo ""; fi + +echo " +" diff --git a/webroot/allegro/index.shs b/webroot/allegro/index.shs new file mode 100644 index 0000000..0fe519a --- /dev/null +++ b/webroot/allegro/index.shs @@ -0,0 +1,8 @@ +#!/bin/bash + +source templates/head.sh + +echo "
+ + +
" diff --git a/webroot/allegro/listing.shs b/webroot/allegro/listing.shs new file mode 100755 index 0000000..ce0148b --- /dev/null +++ b/webroot/allegro/listing.shs @@ -0,0 +1,68 @@ +#!/bin/bash +cat webroot/allegro/listing_top.txt + +query="$(echo "${get_data[q]}" | sed -s "s/ /%20/g;s/+/%20/g")" +query_nice=$(echo ${get_data[q]} | sed -s "s/+/ /g;") +[[ ${get_data[order]} ]] && order=${get_data[order]} || order='p' + +echo "Searching for '$query_nice'" + +IFS=$'\n' +data=$(curl "https://allegro.pl/listing?string=$query&order=$order" | sed -E 's/<\/article>/\n/g' | grep -ohE "allegro.pl/oferta(.*)") + +cost=($(echo "$data" | grep -Eoh "span class=\"[A-Za-z0-9_]{12}\">([0-9]+|[0-9]+ [0-9]+),<\/span>[0-9]+" | sed -E 's/span class=\"[A-Za-z0-9_]{12}\">//g;s///g;s/<\/span>//g' | grep -ohE "[a-z0-9].allegroimg.com/s[0-9]+/[a-z0-9]{6}/[a-z0-9]{28}/(.*)")) +name=($(echo "${data}" | sed -E 's/<\/a>/\n/g' | grep -ohE 'title="">(.*)' | sed -s 's/title="">//g')) +links=($(echo "${data}" | sed -E 's/"(.*)//g')) + +for (( i=0; i<${#img[@]}; i++ )) do + #echo "" + + echo " + + + + + + + + +
+ + ${name[$i]} + + + + + + +
+ + + + Kup Teraz! ${cost[$i]} zł + + + +
+ + z dostawą: + ??? zł + +
+ + + + Popularność: ??? + + + Do końca: ??? + + + + " + + +done + +cat webroot/allegro/listing_bottom.txt diff --git a/webroot/allegro/listing_bottom.txt b/webroot/allegro/listing_bottom.txt new file mode 100644 index 0000000..4178eaa --- /dev/null +++ b/webroot/allegro/listing_bottom.txt @@ -0,0 +1,820 @@ + + + + + + + + + + + +
+
+ +  1  + + 2 + + 3 + + ... 179 + + + +
+
+ Wersja do druku + +
+ + + + + +
+ + +
+

+ Korzystanie z serwisu oznacza akceptację regulaminu +

+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/webroot/allegro/listing_top.txt b/webroot/allegro/listing_top.txt new file mode 100644 index 0000000..5b7852d --- /dev/null +++ b/webroot/allegro/listing_top.txt @@ -0,0 +1,1321 @@ + + + + + + + + + Allegro.pl - Więcej niż aukcje. Najlepsze oferty na największej platformie handlowej. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + +
+
+

Podgląd strony do wydruku

+

Niniejszy komunikat nie zostanie wydrukowany.

+
+ +
+ + +
+
+
+
+
+

ibm

- znaleziono 8945 przedmiotów. +
+
+   +   +
+ + + +
+
+
+
+
+ Dodaj do ulubionych kryteriów wyszukiwania
+ RSS dla tych wyników wyszukiwania
+
+
+
+ + + + + +
+ + + + + + +
+ + +
+
+

+
    +
+
+
+
+ + + + + +
+ +
+ + + + + + +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+
+ Porównanie + + Widok:  + + + +
+
+ Strona: + + +   z 179 +
+
+ +Sortuj według: + + +
+ + + + +
+ + + + + + + + + + + + + + diff --git a/webroot/boards/i/empty b/webroot/boards/i/empty new file mode 100644 index 0000000..e69de29 diff --git a/webroot/boards/index.shs b/webroot/boards/index.shs new file mode 100644 index 0000000..a710133 --- /dev/null +++ b/webroot/boards/index.shs @@ -0,0 +1,34 @@ +#!/bin/bash +domainprefix='https://megumin.tech/boards' + +meta[title]='bashchan' +meta[css]='style.css' +source templates/head.sh + +echo " +
+
+ bashchan
- a place for all your shitposts +
+" +IFS=$'\n' +for i in $(ls -t storage/threads); do + IFS=':' + array=($(cat storage/threads/$i | head -n 1)) + echo "
" + if [[ ${array[1]} != '' ]]; then + echo "${array[1]} | " + fi + echo "${array[0]}
${array[2]}

" +done + + +echo "

Submit a new thread

+
+ + +
+
+ + + " diff --git a/webroot/boards/post.shs b/webroot/boards/post.shs new file mode 100644 index 0000000..58d4c42 --- /dev/null +++ b/webroot/boards/post.shs @@ -0,0 +1,48 @@ +#!/bin/bash + +title=$(cat ${post_multipart[2]} | sed -s 's//g;s/://g' | tr -d '\n\r') +img=${post_multipart[4]} +img_name=$(basename ${post_multipart[4]}) +rel=$(cat ${post_multipart[0]} | sed -E 's/' ]]; then + echo "Post something!" + return 1 +fi + +if session_verify ${cookies[sh_session]}; then + username=$(session_get_username ${cookies[sh_session]}) +else + username='Anon' +fi + +if [[ $rel == *"new"* ]]; then + rel=$(($(ls storage/threads/ | wc -l)+1)) + touch "storage/threads/$rel" +fi + +if [[ -f "storage/threads/$rel" ]]; then + echo "$username:$title:$msg:$img_name" | sed -E "s/\r//g" >> "storage/threads/$rel" +else + echo "No such thread!!" + return 1 +fi + +meta[redirect]="thread.shs?id=$rel" + +source templates/head.sh + +echo "Submitted succesfully.
+Click here if you're not redirected" diff --git a/webroot/boards/style.css b/webroot/boards/style.css new file mode 100644 index 0000000..8d1b432 --- /dev/null +++ b/webroot/boards/style.css @@ -0,0 +1,42 @@ +.center { + margin-left: auto; + margin-right: auto; + max-width: 100%; + display: block; + text-align: center; + margin-bottom: 30px; +} + +.file { + width: 225px +} +.msg { + width: 325px; + height: 125px; +} +.title { + width: 318px; +} +.submit { + width: 95px; +} +.pic { + width: 200px; +} + +.thread_title { + color: #f44; +} + +.poster { + color: #4f4; +} + +.post { + margin: 5px; + background-color: #222; +} +.nolinkdecoration, .nolinkdecoration > div { + color: #ccc; + text-decoration: none; +} diff --git a/webroot/boards/thread.shs b/webroot/boards/thread.shs new file mode 100644 index 0000000..4df422d --- /dev/null +++ b/webroot/boards/thread.shs @@ -0,0 +1,46 @@ +#!/bin/bash +domainprefix='https://megumin.tech/boards' + +id=${get_data[id]} +if [[ $id == '' ]]; then + return 1 +elif [[ $id == *".."* ]]; then + return 1 +fi + +meta[css]='style.css' +meta[title]="Thread #$id" +source templates/head.sh + +echo " +
+
+ bashchan
- a place for all your shitposts +
+" + +IFS=$'\n' +for i in $(cat storage/threads/$id); do + IFS=':' + array=($i) + echo "
" + if [[ ${array[1]} != '' ]]; then + echo "${array[1]} | " + fi + echo "${array[0]}
" + if [[ -a "$pwd/i/${array[3]}" ]]; then + echo "" + fi + echo "${array[2]}
" +done + + +echo "
+ + +
+
+ + + +" diff --git a/webroot/img/branding_chinacat.png b/webroot/img/branding_chinacat.png new file mode 100644 index 0000000000000000000000000000000000000000..6dd0b4c82fb7a28d0b58bbdf76296952ae614098 GIT binary patch literal 7701 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 G67^r^m-r+A literal 0 HcmV?d00001 diff --git a/webroot/img/branding_pxplus.png b/webroot/img/branding_pxplus.png new file mode 100644 index 0000000000000000000000000000000000000000..a2201a6caa38d4d4bcc3c0fd663308aaaf93dca0 GIT binary patch literal 4641 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 keZPj`|BdMY@I7{O4 +" +if [[ ! ${cookies[sh_session]} ]]; then + echo "" +else + echo "
Logged in as ${cookies[username]}| Log out
" +fi +echo " +

HTTP.sh - a quick and dirty webserver, written in Bash

+ +

+Although we've seen several attempts to create a Bash web framework, all of them fell flat one way or another.
+We've decided to change that. Did we succeed? You be the judge! +

+ +

Download

+

+This web server was tested as much as the time allowed, but we can't say for certain that it's bug free.
+If you want to check out our (dirty) code, download the current tarball.

+We also can't guarantee that HTTP.sh is asbestos free, so proceed with caution. +

+ +

Dependencies

+
    +
  1. Bash or 100% compatible shell
  2. +
  3. Ncat - nc/nc.traditional WILL NOT work
  4. +
  5. GNU coreutils (dd, base64 and others)
  6. +
  7. pkill
  8. +
  9. mktemp
  10. +
  11. sha1sum, sha256sum
  12. +
  13. curl (only for a few demos)
  14. +
  15. certbot (only if you'd like to get a SSL cert) +
+ +

Demos

+
    +
  1. bashchan (an imageboard)
  2. +
  3. bashbin (a pastebin)
  4. +
  5. bashtube (a YouTube frontend)
  6. +
  7. bashurl (a URL shortener)
  8. +
  9. bashupload (a file uploader)
  10. +
  11. bashallgero (a frontend for a Polish auction site)
  12. +
  13. listing (just a file listing, but it looks mighty cool)
  14. +
+ +
+Made by reds, selfisekai and ptrcnull. IF YOU LOG IN, THIS SITE WILL STORE COOKIES ON YOUR PERSONAL COMPUTING DEVICE" diff --git a/webroot/login.shs b/webroot/login.shs new file mode 100755 index 0000000..63e818b --- /dev/null +++ b/webroot/login.shs @@ -0,0 +1,30 @@ +#!/bin/bash + +if [[ ${post_data[login]} != '' && ${post_data[password]} != '' ]]; then + login ${post_data[login]} ${post_data[password]} + status=$? + if [[ $status == 0 ]]; then + echo ${get_data[r]} > /dev/stderr + if [[ ${get_data[r]} == '' ]]; then + meta[redirect]='/' + else + meta[redirect]="$(echo ${get_data[r]} | sed -s 's/Log in... +
+ +
+ +
+ + +(please make sure that you're connecting over SSL)" diff --git a/webroot/logout.shs b/webroot/logout.shs new file mode 100755 index 0000000..538ef39 --- /dev/null +++ b/webroot/logout.shs @@ -0,0 +1,7 @@ +#!/bin/bash + +logout +meta[redirect]='/' +source templates/head.sh + +echo "Logged out successully. Redirecting.." diff --git a/webroot/pastebin/index.shs b/webroot/pastebin/index.shs new file mode 100755 index 0000000..fcd27a2 --- /dev/null +++ b/webroot/pastebin/index.shs @@ -0,0 +1,56 @@ +#!/bin/bash +domainprefix="https://paste.megumin.tech/" + +if [[ ${post_data[paste]} ]]; then + filepath=$(mktemp -p $pwd XXX) + filename=$(basename $filepath) + if [[ ${post_data[public]} == "on" ]]; then + echo $filename >> $pwd/list + fi + if session_verify ${cookies[sh_session]}; then + echo "$filename:$(session_get_username ${cookies[sh_session]})" >> storage/pastes + fi + echo -e $(echo "${post_data[paste]}" | sed -E 's/\+/ /g;s/\%/\\x/g') > $filepath + meta[redirect]="$domainprefix$filename" +fi + +source templates/head.sh + +echo " + +
+ + +
+ + +" + +if session_verify ${cookies[sh_session]}; then + echo "

Your pastes:

" + pastes=$(grep -E "$(session_get_username ${cookies[sh_session]})\$" storage/pastes) + if [[ $pastes != '' ]]; then + echo "
    " + for i in $pastes; do + IFS=':' + array=($i) + echo "
  1. ${array[0]}
  2. " + done + echo "
" + else + echo "You currently do not have any pastes." + fi +else + echo "If you log in, we'll be able to show you your paste history here :)" +fi + +echo "

Latest public pastes:

    " +public=$(tac $pwd/list | head -n 10) + +IFS=$'\n' +for i in $public; do + echo "
  1. $i
  2. " +done +unset IFS +echo "" + diff --git a/webroot/pastebin/list b/webroot/pastebin/list new file mode 100644 index 0000000..e69de29 diff --git a/webroot/register.shs b/webroot/register.shs new file mode 100755 index 0000000..4913367 --- /dev/null +++ b/webroot/register.shs @@ -0,0 +1,25 @@ +#!/bin/bash + +if [[ ${post_data[login]} != '' && ${post_data[password]} != '' ]]; then + register ${post_data[login]} ${post_data[password]} + status=$? + if [[ $status == 0 ]]; then + meta[redirect]='/' + fi +fi + +source templates/head.sh + +if [[ $status == 1 && $reason != '' ]]; then + echo $reason +fi + +echo "

    Register

    +
    + +
    + +
    + + +(please make sure that you're connecting over SSL)" diff --git a/webroot/shortener/index.shs b/webroot/shortener/index.shs new file mode 100755 index 0000000..b785821 --- /dev/null +++ b/webroot/shortener/index.shs @@ -0,0 +1,35 @@ +#!/bin/bash +domainprefix="https://url.megumin.tech/" +not_found=false + +if [[ ${get_data[u]} ]]; then + id=${get_data[u]} + if [[ -f storage/shortener/$id ]]; then + meta[redirect]=$(cat storage/shortener/$id) + else + not_found=true + fi +fi + +meta[title]="url shortener i guess" +source templates/head.sh + +if [[ $not_found == "true" ]]; then + echo "

    ID not found

    " +else + if [[ ${post_data[url]} ]]; then + if [[ ! -d storage/shortener ]]; then + mkdir storage/shortener + fi + id=$(dd if=/dev/urandom bs=256 count=1 | sha1sum | cut -c 1-8) + link=$(printf $(sed 's/%/\\x/g' <<< ${post_data[url]})) + echo -n $link > storage/shortener/$id + echo "

    URL created: link

    " + else + echo '

    Revolutionary URL shortener

    +
    + + + '; + fi +fi diff --git a/webroot/upload/index.shs b/webroot/upload/index.shs new file mode 100755 index 0000000..1b017f2 --- /dev/null +++ b/webroot/upload/index.shs @@ -0,0 +1,18 @@ +#!/bin/bash +source templates/head.sh +domainprefix="https://f.megumin.tech/" + +if [[ ${post_multipart} != '' ]]; then + for i in ${post_multipart[@]}; do + asdf=$(mktemp -p $(dirname ${r[uri]}) XXX) + relative=$(realpath --relative-to "$(dirname ${r[uri]})" $asdf) + mv "$i" $asdf + rm "$i" + echo "Your uploaded file" + done +else +echo '
    +
    + + ' +fi diff --git a/webroot/yt/fav.shs b/webroot/yt/fav.shs new file mode 100644 index 0000000..f9d0444 --- /dev/null +++ b/webroot/yt/fav.shs @@ -0,0 +1,19 @@ +#!/bin/bash + +if session_verify ${cookies[sh_session]} && [[ ${get_data[v]} != '' ]]; then + title=$(youtube-dl -e "https://youtube.com/watch?v=${get_data[v]}") + if [[ $(cat storage/faves | grep -F "$title" | grep "$(echo ${cookies[username]} | sed -E "s/\r//")") == '' ]]; then + echo "$(session_get_username ${cookies[sh_session]}):${get_data[v]}:$title" >> storage/faves + fi +fi + +source templates/head.sh + +echo "<--- back to main

    Your favourites

    " + +IFS=$'\n' +for i in $(tac storage/faves); do + IFS=':' + array=($i) + echo ""; +done diff --git a/webroot/yt/index.shs b/webroot/yt/index.shs new file mode 100755 index 0000000..2e57b6d --- /dev/null +++ b/webroot/yt/index.shs @@ -0,0 +1,16 @@ +#!/bin/bash +source templates/head.sh + +echo "
    + + + + +

    All user's favourites

    " + +IFS=$'\n' +for i in $(tac storage/faves); do + IFS=':' + array=($i) + echo "

    ${array[@]:2:999}

    Favourited by ${array[0]}
    "; +done diff --git a/webroot/yt/search.shs b/webroot/yt/search.shs new file mode 100755 index 0000000..514f324 --- /dev/null +++ b/webroot/yt/search.shs @@ -0,0 +1,34 @@ +#!/bin/bash +meta[title]="youtube but not really" +source templates/head.sh + +# GOOD LUCK FIXING IT WHEN GOOGLE BREAKS IT LOL + +echo "
    + + + +" + +if [[ ${get_data[q]} ]]; then + query=${get_data[q]} + query_nice=$(echo ${get_data[q]} | sed -s 's/+/ /g') + + echo "

    Searching for '$query_nice'

    " + data='' + while [[ $data == '' ]]; do + data=$(curl -s "https://www.youtube.com/results?search_query=$query&hl=en&hs=en") + done + + + IFS=$'\n' + id=($(echo $data | sed -E 's/<\/a>/\n/g' | grep -ohE 'watch\?v\=[-A-Za-z0-9_]{11}" (.*) rel\="spf-prefetch"' | sed -E 's/watch\?v\=//g;s/" class="yt-uix-tile-link(.*)//g')) + title=($(echo $data | sed -E 's/<\/a>/\n/g' | grep -ohE 'watch\?v\=[-A-Za-z0-9_]{11}" (.*) rel\="spf-prefetch"' | sed -E 's/watch\?v\=[-A-Za-z0-9_]{11}" class\="yt-uix-tile-link(.*)title\="/ /g;s/" rel\="spf-prefetch"//g')) + unset IFS + + for (( i=0; i<${#id[@]}; i++ )); do + echo "
    ${title[$i]}

    " + done +else + echo "search for something will 'ya?" +fi diff --git a/webroot/yt/unfav.shs b/webroot/yt/unfav.shs new file mode 100644 index 0000000..6ed4337 --- /dev/null +++ b/webroot/yt/unfav.shs @@ -0,0 +1,10 @@ +#!/bin/bash + +if session_verify ${cookies[sh_session]} && [[ ${get_data[v]} != '' ]]; then + name=$(session_get_username ${cookies[sh_session]}) + vid=$(echo -n ${get_data[v]} | sed -E 's/\r//g') + sed -i "/^$name:$vid/d" storage/faves +fi +meta[redirect]='fav.shs' + +source templates/head.sh diff --git a/webroot/yt/watch.shs b/webroot/yt/watch.shs new file mode 100755 index 0000000..cc55bd8 --- /dev/null +++ b/webroot/yt/watch.shs @@ -0,0 +1,59 @@ +#!/bin/bash + +# fetching recommended disabled for speed + +#for i in $(curl https://www.youtube.com/watch?v=${get_data[v]} | grep -ohE "watch\?v\=[A-zaz0-9]{11}" | uniq | cut -c 9-19); do +# echo "

    "; +#done + +if [[ ${get_data[v]} ]]; then + video=$(youtube-dl -J "http://youtube.com/watch?v=${get_data[v]}") + if [[ $video == '' ]]; then + video=$(youtube-dl -J "http://youtube.com/watch?v=${get_data[v]}") + if [[ $video == '' ]]; then + return + fi + fi + #echo "http://youtube.com/watch?v=${get_data[v]}" > /dev/stderr + title=$(echo $video | jq -r '.title') + meta[title]=$title + source templates/head.sh + IFS=$'\n' + urls=($(echo $video | jq -r '.formats[] | select(.format_id == "22" or .format_id == "18").url')) + unset IFS + if [[ ${urls[1]} != '' ]]; then + url=${urls[1]} + else + url=${urls[0]} + fi + echo "
    + + + +

    +

    $title

    +
    +
    + Uploaded by $(echo $video | jq -r '.uploader') on $(date -d "$(echo $video | jq -r '.upload_date')" "+%d %B %Y") +
    +
    + $(echo $video | jq -r '.view_count') views
    + $(echo $video | jq -r '.like_count') likes, $(echo $video | jq -r '.dislike_count') dislikes.
    " + if [[ ${cookies[sh_session]} ]]; then + if [[ $(cat storage/faves | grep $(echo -n ${cookies[username]} | sed -E 's/\r//g') | grep ${get_data[v]}) == '' ]]; then + echo "Add to favourites
    " + else + echo "Remove from favourites
    " + fi + else + echo "Log in to add this video to your favourites!
    " + fi + echo "

    +
    +
    + Description:
    $(echo $video | jq -r '.description' | sed -E 's/$/
    /g')
    +
    "; +else + source templates/head.sh + echo "pls add ?v param i'm still WiP" +fi
lista promowanych przedmiotów
+ + + + + Nazwa + + + + Cena + + + + z dostawą + + + + Popularność + + + + Do końca +