Initial commit, importing from tarball
commit
b8f3169f57
|
@ -0,0 +1,157 @@
|
|||
### GNU LESSER GENERAL PUBLIC LICENSE
|
||||
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
<https://fsf.org/>
|
||||
|
||||
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.
|
|
@ -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.
|
|
@ -0,0 +1 @@
|
|||
cfg[title]='Laura is cute :3'
|
|
@ -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'
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -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]}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
printf "HTTP/1.0 401 Unauthorized
|
||||
WWW-Authenticate: Basic realm=\"${cfg[auth_realm]}\"
|
||||
${cfg[extra_headers]}\r\n"
|
|
@ -0,0 +1,4 @@
|
|||
printf "HTTP/1.0 403 Forbidden
|
||||
${cfg[extra_headers]}\r\n\r\n"
|
||||
source templates/head.sh
|
||||
echo "<h1>403: You've been naughty</h1>"
|
|
@ -0,0 +1,4 @@
|
|||
printf "HTTP/1.0 404 Not Found
|
||||
${cfg[extra_headers]}\r\n\r\n"
|
||||
source templates/head.sh
|
||||
echo "<h1>404 Not Found</h1>"
|
|
@ -0,0 +1,33 @@
|
|||
printf "HTTP/1.0 200 OK
|
||||
${cfg[extra_headers]}\r\n\r\n"
|
||||
|
||||
source templates/head.sh
|
||||
|
||||
printf "<h1>Index of $([[ ${r[url]} == '' ]] && echo '/' || echo ${r[url]})</h1>"
|
||||
|
||||
if [[ ${cookies[username]} != '' ]]; then
|
||||
echo "Logged in as ${cookies[username]}"
|
||||
fi
|
||||
|
||||
printf "<table>
|
||||
<tr>
|
||||
<th>File</th>
|
||||
<th>Size</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href='../'>..</a></td><td></td><td></td>
|
||||
</tr>"
|
||||
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 "<tr><td><a href='$(echo -ne ${r[url]})/$i/'>$i</a></td><td><DIR></td><td>${stats[5]} ${stats[6]} ${stats[7]}</td></tr>"
|
||||
else
|
||||
printf "<tr><td><a href='$(echo -ne ${r[url]})/$i'>$i</a></td><td>${stats[4]}B</td><td>${stats[5]} ${stats[6]} ${stats[7]}</td></tr>"
|
||||
fi
|
||||
done
|
||||
|
||||
printf "</table><p><i>HTTP.sh server on ${r[host]}</i></p><p>laura is cute</p>"
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
#!/bin/bash
|
||||
echo '<!DOCTYPE html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">'
|
||||
|
||||
if [[ ${meta[title]} ]]; then echo "<title>${meta[title]} - ${cfg[title]}</title>"; else echo "<title>${cfg[title]}</title>"; fi
|
||||
if [[ ${meta[author]} ]]; then echo "<meta name='author' content='${meta[author]}'>"; fi
|
||||
if [[ ${meta[description]} ]]; then echo "<meta name='description' content='${meta[description]}'>"; fi
|
||||
if [[ ${meta[keywords]} ]]; then echo "<meta name='keywords' content='${meta[keywords]}'>"; fi
|
||||
if [[ ${meta[refresh]} ]]; then echo "<meta http-equiv='refresh' content='${meta[refresh]}'>"; fi
|
||||
if [[ ${meta[redirect]} ]]; then echo "<meta http-equiv='refresh' content='0; URL=${meta[redirect]}'>"; fi
|
||||
if [[ ${meta[css]} ]]; then echo "<link rel='stylesheet' type='text/css' href='${meta[css]}'/>"; fi
|
||||
if [[ ${meta[title]} ]]; then echo "<meta property='og:title' content='${meta[title]}'>"; fi
|
||||
#if [[ ${meta[og:type]} ]]; then echo "<meta property='og:type' content='${meta[og:type]}'>"; fi
|
||||
if [[ ${cfg[url]} ]]; then echo "<meta property='og:url' content='${cfg[url]}'>"; fi
|
||||
#if [[ ${meta[og:image} ]]; then echo "<meta property='og:image' content='${meta[og:image]}'>"; fi
|
||||
if [[ ${meta[lang]} ]]; then echo "<meta property='og:locale' content='${meta[lang]}'>"; fi
|
||||
if [[ ${meta[description]} ]]; then echo "<meta property='og:description' content='${meta[description]}'>"; fi
|
||||
|
||||
echo "<style>
|
||||
body {
|
||||
background-color: #1a1a1a;
|
||||
color: #ccc;
|
||||
}
|
||||
a {
|
||||
color: #3d3;
|
||||
}
|
||||
a:visited {
|
||||
color: #3b3;
|
||||
}
|
||||
tr:nth-child(2n) {
|
||||
background-color: #333;
|
||||
}
|
||||
</style>
|
||||
</head>"
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
source templates/head.sh
|
||||
|
||||
echo "<form action='listing.shs'>
|
||||
<input type='text' name='q'>
|
||||
<input type='submit' value='Search'>
|
||||
</form>"
|
|
@ -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>,<\/span><span class=\"[A-Za-z0-9_]{12}\">[0-9]+" | sed -E 's/span class=\"[A-Za-z0-9_]{12}\">//g;s/<span>//g;s/<\/span><//g'))
|
||||
img=($(echo "${data}" | sed -E 's/\" [a-z]{3,5}\="/\n/g;s/,/\n/g;s/ [0-9]+w//g;s/" \/>//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 "<div><a href='https://${links[$i]}'><img src='https://${img[$i]}'>${cost[$i]}PLN<br><b>${name[$i]}</b></a></div>"
|
||||
|
||||
echo "
|
||||
<!-- ITEM BEGIN -->
|
||||
<tr>
|
||||
<td class='cellPhoto'>
|
||||
<a href='${links[$i]}' class='iImg' title='${name[$i]}'><img src='https://${img[$i]}'></a>
|
||||
</td>
|
||||
|
||||
|
||||
<td class='cellName'>
|
||||
<div>
|
||||
<a href='https://${links[$i]}' class='alleLink iTitle'>
|
||||
<span>${name[$i]}</span>
|
||||
</a>
|
||||
<span class='listingParams'>
|
||||
</span>
|
||||
<span>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class='cellPrice'>
|
||||
<span class='iPriceBN'><span>Kup Teraz!</span> ${cost[$i]} zł</span>
|
||||
</td>
|
||||
|
||||
<td class='cellTrans'>
|
||||
<div>
|
||||
<span class='iPriceBND'>
|
||||
<span>z dostawą:</span>
|
||||
<span class='listingPostagePrice'>??? zł</span>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class='cellOffer'>
|
||||
<span class='iOffer'><span>Popularność:</span> ???</span> </td>
|
||||
|
||||
<td class='cellTime alert'>
|
||||
<span class='iTime'><span>Do końca:</span> <font color='#ff0000'>???</font></span>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- ITEM END -->
|
||||
"
|
||||
|
||||
|
||||
done
|
||||
|
||||
cat webroot/allegro/listing_bottom.txt
|
|
@ -0,0 +1,820 @@
|
|||
|
||||
|
||||
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div><!--/tabMainBox-->
|
||||
</div><!--/tabContent-->
|
||||
|
||||
<div id="pagerBottom">
|
||||
<div class="td-pager-bottom">
|
||||
|
||||
<strong class="orange large">1</strong>
|
||||
|
||||
<a class="alleLink" href="/web/20120904144913/http://allegro.pl/listing.php/search?p=2&sg=0&string=ibm"><span>2</span></a>
|
||||
|
||||
<a class="alleLink" href="/web/20120904144913/http://allegro.pl/listing.php/search?p=3&sg=0&string=ibm"><span>3</span></a>
|
||||
|
||||
... <a class="alleLink" href="/web/20120904144913/http://allegro.pl/listing.php/search?p=179&sg=0&string=ibm"><span>179</span></a>
|
||||
|
||||
|
||||
<a href="/web/20120904144913/http://allegro.pl/listing.php/search?p=2&sg=0&string=ibm" class="arrRight-bottom" title="Następna"></a>
|
||||
</div>
|
||||
</div>
|
||||
<a id="idPrintGo" href="" class="smaller alleLink noprint"><span>Wersja do druku</span></a>
|
||||
|
||||
<div id="compareItems" class="pl"></div>
|
||||
|
||||
|
||||
<!-- Footer start -->
|
||||
</div> <!-- /pagecontent1 -->
|
||||
|
||||
<div id="footerContentBox" class="newSpecial">
|
||||
<a href="#top" id="toTop"></a>
|
||||
<div class="ohidden">
|
||||
<div id="footerAbout">
|
||||
<h2>O Allegro</h2>
|
||||
<ul>
|
||||
<li><a href="/web/20120904144913/http://allegro.pl/country_pages/1/0/marketing/about.php">O nas</a></li>
|
||||
<li><a href="https://web.archive.org/web/20120904144913/http://kariera.allegro.pl/">Praca w Grupie Allegro</a></li>
|
||||
<li><a href="/web/20120904144913/http://allegro.pl/country_pages/1/0/marketing/allforplanet/">Fundacja All For Planet</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="footerBuy">
|
||||
<h2>Bezpieczne zakupy</h2>
|
||||
<ul>
|
||||
<li><a href="https://web.archive.org/web/20120904144913/http://uslugi.allegro.pl/pok/">Program Ochrony Kupujących</a></li>
|
||||
<li><a href="/web/20120904144913/http://allegro.pl/RightsProtectionCooperationProgram.php">Współpraca w Ochronie Praw</a></li>
|
||||
<li><a href="https://web.archive.org/web/20120904144913/http://uslugi.allegro.pl/sa/">Standard Allegro</a></li>
|
||||
<li><a href="https://web.archive.org/web/20120904144913/http://uslugi.allegro.pl/payu/">PayU</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="footerSell">
|
||||
<h2>Skuteczna Sprzedaż</h2>
|
||||
<ul>
|
||||
<li><a href="/web/20120904144913/http://allegro.pl/InfoPage/SellManager.php">Menedżer Sprzedaży</a></li>
|
||||
<li><a href="/web/20120904144913/http://allegro.pl/country_pages/1/0/produkty-jak.php">Katalog produktów</a></li>
|
||||
<li><a href="/web/20120904144913/http://allegro.pl/show_shop.php">Sklepy Allegro</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="footerMobile">
|
||||
<h2>Mobilne Allegro</h2>
|
||||
<ul>
|
||||
<li><a rel="external" href="https://web.archive.org/web/20120904144913/http://mobilne.allegro.pl/">Aplikacja na Twój telefon</a></li>
|
||||
<li><a href="https://web.archive.org/web/20120904144913/http://m.allegro.pl/">Strona mobilna</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="reg">
|
||||
Korzystanie z serwisu oznacza akceptację <a href="/web/20120904144913/http://allegro.pl/country_pages/1/0/user_agreement.php" class="alleLink"><span>regulaminu</span></a>
|
||||
</p>
|
||||
</div><!-- /footerContentBox -->
|
||||
|
||||
<script type="text/javascript" src="https://web.archive.org/web/20120904144913js_/http://static.allegrostatic.pl/site_images/1/0/js/ado.js"></script>
|
||||
|
||||
<script src="https://web.archive.org/web/20120904144913js_/http://static.allegrostatic.pl/js/libs/jquery-1.6.1.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script type="text/javascript" charset="utf-8">var $j = jQuery.noConflict();</script>
|
||||
<script src="https://web.archive.org/web/20120904144913js_/http://static.allegrostatic.pl/js/libs/jquery-ui-1.7.2.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="https://web.archive.org/web/20120904144913js_/http://static.allegrostatic.pl/js/gtagb4.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="https://web.archive.org/web/20120904144913js_/http://static.allegrostatic.pl/js/libs/jquery.watermark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="https://web.archive.org/web/20120904144913js_/http://static.allegrostatic.pl/js/scripts/jq_plugins-13.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="https://web.archive.org/web/20120904144913js_/http://static.allegrostatic.pl/js/scripts/mainjs-5.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="https://web.archive.org/web/20120904144913js_/http://static.allegrostatic.pl/js/scripts/showitem-gallery-2.3.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="https://web.archive.org/web/20120904144913js_/http://static.allegrostatic.pl/js/scripts/recommended-gallery-1.1.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="https://web.archive.org/web/20120904144913js_/http://static.allegrostatic.pl/js/scripts/listing-12.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
|
||||
(function($){
|
||||
$(function(){
|
||||
$('#showMoreCats, #hideMoreCats').click(function(){
|
||||
$('#categoriesList .additional, .slideInBtn, .slideOutBtn').toggle(200);
|
||||
return false;
|
||||
});
|
||||
if ( $('.additional').length ){ $('.slideOutBtn').show(); }
|
||||
});
|
||||
})(jQuery);
|
||||
|
||||
|
||||
(function($){
|
||||
$(function(){
|
||||
$('.priceComparerCeneoLink').click(function(event){
|
||||
baseURI = encodeURIComponent(event.currentTarget.baseURI);
|
||||
targetURI = encodeURIComponent(event.currentTarget.href);
|
||||
$.ajax({
|
||||
url: '/ceneo.php/?url=' + targetURI + '&ref=' + baseURI,
|
||||
dataType: 'json'
|
||||
});
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
|
||||
|
||||
(function ($) {
|
||||
|
||||
/**
|
||||
* Wizard
|
||||
*
|
||||
*/
|
||||
var wizard = function () {
|
||||
|
||||
/**
|
||||
* Protected variables
|
||||
*
|
||||
*/
|
||||
var current = {
|
||||
stepElement: {},
|
||||
stepData: {},
|
||||
optionData: {}
|
||||
},
|
||||
paginElements = {
|
||||
prev: {},
|
||||
steps: {}
|
||||
},
|
||||
prevSteps = [],
|
||||
showedSteps = {},
|
||||
procesingLayer,
|
||||
isOnLayer = false,
|
||||
params = {},
|
||||
hasStorage = (function () {
|
||||
try {
|
||||
localStorage.setItem('wizTest', 'wizTest');
|
||||
localStorage.removeItem('wizTest', 'wizTest');
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
})(),
|
||||
optimizerCombination = (typeof utmx !== 'undefined' && typeof utmx('combination') !== 'undefined') ? '&combination=' + utmx('combination') : '';
|
||||
|
||||
|
||||
/**
|
||||
* Init
|
||||
*
|
||||
* @return void
|
||||
* @api publiuc
|
||||
*/
|
||||
var init = function (callback) {
|
||||
var contener = $('#wizardContent');
|
||||
// params = setConfig()
|
||||
|
||||
paginElements.prev = $('#prev-step a');
|
||||
paginElements.steps = $('#stepsPagin li.pag');
|
||||
|
||||
// Ustawienia początkowych danych
|
||||
current.stepElement = contener.children('div'); // Aktulnie wybrany krok (HTML Element)
|
||||
showedSteps[current.stepElement.attr('id')] = true; // ID aktualnie wybranego kroku, zapisujemy w tablicy - cache
|
||||
current.stepData = $(current.stepElement).data('wizard-step'); // Pobieramy dane o aktualnym kroku (nr kroku i sciezke poprzednich krokow)
|
||||
current.optionData = $(current.stepElement).find('li.current').data('wizard-option') || {};
|
||||
|
||||
// Odświeżenie stanów buttonów nawigacji
|
||||
refreshPagin();
|
||||
|
||||
// Zmiana kroku odbywa się po zmienia hasha
|
||||
$(window).bind('hashchange', function () {
|
||||
if (window.location.hash === '') {
|
||||
changeStep('1-1', true);
|
||||
} else if (/#wiz-cur/.test(window.location.hash)) {
|
||||
if (isOnLayer) {
|
||||
if (!$('#wizard').is(':visible')) {
|
||||
showWizardOnLayer.showWizard();
|
||||
}
|
||||
}
|
||||
changeStep(window.location.hash.split('#wiz-cur-')[1], true);
|
||||
} else {
|
||||
procesingLayerOpen();
|
||||
}
|
||||
});
|
||||
|
||||
// Wybór opcji w kroku
|
||||
contener.delegate('a', 'click', function (e) {
|
||||
var $this = $(this);
|
||||
|
||||
// Zaznaczenie wybranego elementu
|
||||
$(current.stepElement).find('ul li').removeClass('current');
|
||||
$this.parent().addClass('current');
|
||||
|
||||
// Pobranie danych wybranej opcji
|
||||
current.optionData = $this.parent().data('wizard-option');
|
||||
|
||||
if (window.location.href === this.href) {
|
||||
wiz.showWizardOnLayer.closeWizard();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (/wizard/.test(this.href)) {
|
||||
procesingLayerOpen();
|
||||
if (hasStorage) {
|
||||
localStorage.setItem('wizLastOpt', current.optionData.eq);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Jeżeli w url'u są kroki wizarda, to odpalamy go i ustawiamy aktualną pozycją
|
||||
if (/#wiz-cur-/.test(window.location.hash)) {
|
||||
var id = 'wizard-step-' + prepareStepId(window.location.hash.split('wiz-cur-')[1]);
|
||||
if (typeof showedSteps[id] !== 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
changeStep(window.location.hash.split('wiz-cur-')[1], true, function () {
|
||||
if (hasStorage) {
|
||||
if (typeof localStorage.wizLastOpt !== 'undefined') {
|
||||
selectCurrentOption(localStorage.wizLastOpt, function () {
|
||||
localStorage.removeItem('wizLastOpt');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set config and add config class to the wizard wrapper
|
||||
*
|
||||
* @return params <Object>
|
||||
* @api private
|
||||
*/
|
||||
// var setConfig = function () {
|
||||
// var str = $('#wizard').attr('class'),
|
||||
// opts = {};
|
||||
|
||||
// opts.icons = (/icons/.test(str)) ? true: false;
|
||||
// opts.doubleClick = (/doubleClick/.test(str)) ? true : false;
|
||||
|
||||
// return opts;
|
||||
// };
|
||||
|
||||
|
||||
/**
|
||||
* Refresh pagin - refresh state and href in navigation buttons
|
||||
*
|
||||
* @return void
|
||||
* @api private
|
||||
*/
|
||||
var refreshPagin = function () {
|
||||
// Uaktualnienie buttona prev
|
||||
if (current.stepData.nr > 1) {
|
||||
paginElements.prev.attr('href', '#wiz-cur-' + current.stepData.prevSteps[current.stepData.nr - 2]);
|
||||
paginElements.prev.parent().removeClass('disabled');
|
||||
} else {
|
||||
paginElements.prev.attr('href', '#wiz-prev');
|
||||
paginElements.prev.parent().addClass('disabled');
|
||||
}
|
||||
|
||||
// Uaktualnienie stanu w numerach kroków
|
||||
paginElements.steps.removeClass('current');
|
||||
$(paginElements.steps).eq(current.stepData.nr - 1).addClass('current');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Change step
|
||||
*
|
||||
* @param stepData <string> - Next step path
|
||||
* @param direction <bool> - Next (true) or prev (false)
|
||||
* @return void
|
||||
* @api private
|
||||
*/
|
||||
var changeStep = function (stepData, direction, callback) {
|
||||
// Pobieranie ID kroku z danych z hrefa
|
||||
var stepId = 'wizard-step-' + prepareStepId(stepData),
|
||||
currentOptionNr;
|
||||
|
||||
// Sprawdzamy czy istnieje krok, jak nie to go tworzymy
|
||||
if (!showedSteps[stepId]) {
|
||||
procesingLayerOpen();
|
||||
createStep(stepData, stepId, function () {
|
||||
changeStep(stepData, direction, callback);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Jeżeli się cofamy, to czyścimy wybraną z aktualnego kroku
|
||||
$(current.stepElement).find('ul li').removeClass('current');
|
||||
|
||||
// Ukrywamy poprzedni, wyswietlamy następny krok
|
||||
procesingLayerClose();
|
||||
$(current.stepElement).hide().removeClass('current');
|
||||
current.stepElement = $('#' + stepId).fadeIn(1000);
|
||||
|
||||
currentOptionNr = getCurrentOptNr(stepData);
|
||||
if (currentOptionNr) {
|
||||
selectCurrentOption(currentOptionNr);
|
||||
} else {
|
||||
current.optionData = {};
|
||||
}
|
||||
|
||||
// Aktualizujemy dane kroku
|
||||
current.stepData = current.stepElement.data('wizard-step');
|
||||
|
||||
// Odświeżamy stan elementów nawigacji
|
||||
refreshPagin();
|
||||
|
||||
if (typeof callback !== 'undefined') {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create step - Create and append step HTML structure
|
||||
*
|
||||
* @param stepData <string> - step string like 1-1-3|2-1
|
||||
* @param stepId <string> - step ID in DOM
|
||||
* @param callback <function> callback
|
||||
* @return void
|
||||
* @api private
|
||||
*/
|
||||
var createStep = function (stepData, stepId, callback) {
|
||||
$.ajax({
|
||||
url: '/Showcat/Index.php/getWizardStep',
|
||||
data: {
|
||||
id: 2,
|
||||
stepString: stepData
|
||||
},
|
||||
dataType: 'JSON',
|
||||
success: function (data) {
|
||||
var options = data.wizard.step.options,
|
||||
frag = document.createDocumentFragment(),
|
||||
stepTitle = document.createElement('h2'),
|
||||
stepHTML = document.createElement('div'),
|
||||
ul = document.createElement('ul'),
|
||||
imgData = (function () {
|
||||
var data = {};
|
||||
data.width = 130,
|
||||
data.height = 100,
|
||||
data.ext = '.png'
|
||||
|
||||
return data;
|
||||
})();
|
||||
|
||||
stepTitle.innerHTML = data.wizard.step.title;
|
||||
stepHTML.id = stepId;
|
||||
$(stepHTML).addClass('step');
|
||||
|
||||
stepHTML.setAttribute('data-wizard-step', '{"nr":"'+ (data.wizard.prevSteps.length + 1) +'","prevSteps":'+ toJsonString(data.wizard.prevSteps) +'}');
|
||||
|
||||
for (var i = 0, optionsLen = options.length; i < optionsLen; i++) {
|
||||
var li = document.createElement('li'),
|
||||
a = document.createElement('a'),
|
||||
img = document.createElement('img'),
|
||||
title = document.createElement('h3'),
|
||||
href = (options[i].query === '') ? '#wiz-cur-' + options[i].nextStep : options[i].query + optimizerCombination + window.location.hash;
|
||||
|
||||
img.src = 'https://web.archive.org/web/20120904144913/http://static.allegrostatic.pl/site_images/1/0' + options[i].thumb + imgData.ext;
|
||||
img.width = imgData.width;
|
||||
img.height = imgData.height;
|
||||
title.appendChild(document.createTextNode(options[i].text));
|
||||
|
||||
|
||||
a.setAttribute('href', href);
|
||||
a.appendChild(img);
|
||||
a.appendChild(title);
|
||||
li.appendChild(a);
|
||||
li.setAttribute('data-wizard-option', '{"nextStep":"'+ options[i].nextStep +'","query":"'+ options[i].query +'","eq":"'+ i +'"}');
|
||||
frag.appendChild(li);
|
||||
}
|
||||
|
||||
stepHTML.appendChild(stepTitle);
|
||||
ul.appendChild(frag);
|
||||
stepHTML.appendChild(ul);
|
||||
document.getElementById('wizardContent').appendChild(stepHTML);
|
||||
showedSteps[stepId] = true;
|
||||
callback();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Show wizard on layer
|
||||
*
|
||||
* @param link <jQuery HTML Element> - target
|
||||
* @return void
|
||||
* @api public
|
||||
*/
|
||||
var showWizardOnLayer = (function () {
|
||||
var wizardHTML,
|
||||
overlayHTML,
|
||||
closeWizard,
|
||||
showWizard,
|
||||
start;
|
||||
|
||||
|
||||
start = function (target) {
|
||||
isOnLayer = true;
|
||||
|
||||
/**
|
||||
* Clone and append wizart into layer
|
||||
*/
|
||||
wizardHTML = (function () {
|
||||
var HTML = $('#wizard').clone(true),
|
||||
closeLink = $('<span class="close">X</span>').bind('click', function () {
|
||||
closeWizard();
|
||||
});
|
||||
|
||||
$('#wizard').remove();
|
||||
|
||||
HTML.css({
|
||||
position: 'fixed',
|
||||
display: 'none',
|
||||
width: 750 + 'px',
|
||||
zIndex: 10000
|
||||
}).fadeIn();
|
||||
|
||||
closeLink.appendTo(HTML);
|
||||
|
||||
HTML.addClass('layer');
|
||||
$('body').append(HTML);
|
||||
|
||||
return HTML;
|
||||
})();
|
||||
|
||||
/**
|
||||
* Create overlay
|
||||
*/
|
||||
overlayHTML = (function (callback) {
|
||||
var HTML = $('<div>').css({
|
||||
width: $(window).width() + 'px',
|
||||
height: $(window).height() + 'px',
|
||||
background: '#000',
|
||||
position: 'fixed',
|
||||
zIndex: 8000,
|
||||
top: 0,
|
||||
left: 0,
|
||||
opacity: 0.8,
|
||||
display: 'none'
|
||||
}).appendTo('body');
|
||||
|
||||
callback();
|
||||
return HTML;
|
||||
})(function () {
|
||||
init();
|
||||
});
|
||||
|
||||
/**
|
||||
* Close wizard on Esc
|
||||
*/
|
||||
$(document).bind('keydown', function (e) {
|
||||
if (e.which === 27) {
|
||||
closeWizard();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Attach event for open wizard
|
||||
*/
|
||||
$(target).bind('click', function (e) {
|
||||
e.preventDefault();
|
||||
showWizard();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Close wizard
|
||||
*/
|
||||
closeWizard = function () {
|
||||
overlayHTML.fadeOut();
|
||||
wizardHTML.fadeOut();
|
||||
};
|
||||
|
||||
/**
|
||||
* Show wizard
|
||||
*/
|
||||
showWizard = function () {
|
||||
wizardHTML.css({
|
||||
left: $(window).width() / 2 - 370 + 'px',
|
||||
top: $(window).height() / 2 - (wizardHTML.outerHeight() / 2) + 'px'
|
||||
}).fadeIn();
|
||||
overlayHTML.css({
|
||||
width: $(window).width() + 'px',
|
||||
height: $(window).height() + 'px'
|
||||
}).fadeIn();
|
||||
};
|
||||
|
||||
return {
|
||||
start: start,
|
||||
showWizard: showWizard,
|
||||
closeWizard: closeWizard
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
/**
|
||||
* Open procesing layer - overlay with spinner
|
||||
*
|
||||
* @return void
|
||||
* @api private
|
||||
*/
|
||||
var procesingLayerOpen = function () {
|
||||
procesingLayer = procesingLayer || (function () {
|
||||
var div = $('<div>');
|
||||
div.addClass('processing').css({
|
||||
width: $('#wizard').outerWidth() + 'px',
|
||||
height: $('#wizard').outerHeight() + 'px'
|
||||
});
|
||||
$('#wizard').append(div);
|
||||
return div;
|
||||
})();
|
||||
|
||||
procesingLayer.show();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Close procesing layer - hide overlay with spinner
|
||||
*
|
||||
* @return void
|
||||
* @api private
|
||||
*/
|
||||
var procesingLayerClose = function () {
|
||||
procesingLayer.hide();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get current option
|
||||
*
|
||||
* @return <int> || <bool> - current option number, or false if is not selected
|
||||
* @api private
|
||||
*/
|
||||
var getCurrentOptNr = function (step) {
|
||||
var arr = step.split('|'),
|
||||
par = arr[arr.length-1].split('-');
|
||||
|
||||
if (par.length === 3) {
|
||||
return par[2];
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set current option
|
||||
*
|
||||
* @return void
|
||||
* @api private
|
||||
*/
|
||||
var selectCurrentOption = function (stepNr, callback) {
|
||||
var cur = current.stepElement.find('li').eq(stepNr);
|
||||
|
||||
cur.addClass('current');
|
||||
current.optionData = cur.data('wizard-option');
|
||||
|
||||
if (typeof callback !== 'undefined') {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Prepare Step ID
|
||||
*
|
||||
* @param step <string> step string like 1-1-3|2-1
|
||||
* @return <string> - stepID
|
||||
* @api private
|
||||
*/
|
||||
var prepareStepId = function (step) {
|
||||
var arrSplit = step.split('|'),
|
||||
stepVer = arrSplit[arrSplit.length - 1].split('-');
|
||||
|
||||
return stepVer[0] + '-' + stepVer[1];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* To JSON String - prepare JSON string in array
|
||||
*
|
||||
* @param data <object> - data object
|
||||
* @return <string> - Array at JSON string
|
||||
* @api private
|
||||
*/
|
||||
var toJsonString = function (data) {
|
||||
var str = '[';
|
||||
for (var i = 0, iLen = data.length; i < iLen; i++) {
|
||||
str += '"' + data[i] + '"';
|
||||
if (i !== iLen - 1) {
|
||||
str += ',';
|
||||
}
|
||||
}
|
||||
str += ']';
|
||||
|
||||
return str;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* API
|
||||
*/
|
||||
return {
|
||||
init: init,
|
||||
showWizardOnLayer: showWizardOnLayer
|
||||
};
|
||||
};
|
||||
|
||||
var wiz = new wizard();
|
||||
if (document.getElementById('show-wizard')) {
|
||||
wiz.showWizardOnLayer.start(document.getElementById('show-wizard'));
|
||||
} else {
|
||||
wiz.init();
|
||||
}
|
||||
})(jQuery);
|
||||
|
||||
|
||||
(function($) {
|
||||
// show a hover tooltip if it's defined
|
||||
$('.itemFS').find('.tipContent').each(function() {
|
||||
var toolTip = $(this).html();
|
||||
$(this).parent().helptip({event:'hover','pos':'r', css:'promoTip', body: toolTip});
|
||||
});
|
||||
})(jQuery);
|
||||
|
||||
var ckWidget = function($) {
|
||||
return {
|
||||
widgets: {},
|
||||
|
||||
prepareRequest: function(el) {
|
||||
var req = 'https://web.archive.org/web/20120904144913/http://widgetcokupic.allegro.pl:9968/storage/ck/';
|
||||
var id;
|
||||
el.each(function() {
|
||||
id = $(this).data('product-id');
|
||||
req += 'widget_' + id + ',pluses_' + id + ',';
|
||||
});
|
||||
req += '?callback=?';
|
||||
return req;
|
||||
},
|
||||
|
||||
prepareData: function(data) {
|
||||
for(var i = 0, iLen = data.length; i < iLen; i++) {
|
||||
this.widgets[data[i].id[0]] = {
|
||||
wg: $.parseJSON(data[i].widget[0]),
|
||||
plus: $.parseJSON(data[i].pluses[0])
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
createWidget: function(data, where) {
|
||||
var html = '',
|
||||
rate = parseFloat(data.wg.avgm).toFixed(2),
|
||||
ck_source;
|
||||
|
||||
var setRank = function(ckr) {
|
||||
if (ckr >= 90 ) {
|
||||
return 'first';
|
||||
} else if (ckr >= 80) {
|
||||
return 'second';
|
||||
}
|
||||
return 'third';
|
||||
};
|
||||
|
||||
ck_source = (where === 'listing') ? 'ck_source=1' : 'ck_source=2';
|
||||
|
||||
html += '<div class="ckWidget">';
|
||||
html += '<a class="ckNewRank ' + setRank(data.wg.ckrk) + '" href="' + data.wg.url + '?ck_type=1&' + ck_source + '" target="_blank"></a>';
|
||||
html += '<div class="right">';
|
||||
html += '<em>' + rate + '</em>';
|
||||
html += (where === 'show-item') ?
|
||||
'<p>(według ' + data.wg.opct + ' opinii z Cokupić.pl)</p>' :
|
||||
'<p>(według <a href="' + data.wg.url + '?ck_type=0&' + ck_source + '#productNav" target="_blank">' + data.wg.opct + ' opinii</a> z Cokupić.pl)</p>';
|
||||
html += '</div>';
|
||||
if(where === 'product-page' || where === 'show-item' || where === 'listing') {
|
||||
html += '<p class="plus"><strong>Plusy:</strong> ';
|
||||
for(var i = 0, iLen = data.plus.plus.length; i <= iLen, i < 3; i++) {
|
||||
html += data.plus.plus[i].name + ' (' + data.plus.plus[i].pt + '%), ';
|
||||
}
|
||||
html += '</p>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
return $(html);
|
||||
},
|
||||
|
||||
initList: function(where) {
|
||||
var that = this,
|
||||
paramsIter = 2,
|
||||
rows = $('[data-product-id]');
|
||||
|
||||
$.getJSON(this.prepareRequest(rows), function(data) {
|
||||
if (data.products[0].product != null) {
|
||||
that.prepareData(data.products[0].product);
|
||||
|
||||
rows.each(function() {
|
||||
var id = $(this).data('product-id');
|
||||
if (typeof that.widgets[id] !== 'undefined' && that.widgets[id].wg.ckrk >= 50) {
|
||||
var col = $(this).find('.productListingParams');
|
||||
var paramsWrap = col.find('.params');
|
||||
var widget = that.createWidget(that.widgets[id], where);
|
||||
var params = paramsWrap.find('.paramEntry');
|
||||
|
||||
paramsIter = (where === 'listing') ? 3 : paramsIter;
|
||||
params.slice(paramsIter, params.length).hide();
|
||||
if (where === 'listing') {
|
||||
paramsWrap.after(widget);
|
||||
} else {
|
||||
paramsWrap.before(widget);
|
||||
}
|
||||
widget.slideDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
initSingle: function() {
|
||||
var that = this,
|
||||
wrap = $('[data-product-id]');
|
||||
|
||||
$.getJSON(this.prepareRequest(wrap), function(data) {
|
||||
if (data.products[0].product != null) {
|
||||
that.prepareData(data.products[0].product);
|
||||
|
||||
var id = wrap.data('product-id');
|
||||
|
||||
if (typeof that.widgets[id] !== 'undefined' && that.widgets[id].wg.ckrk >= 50) {
|
||||
var widget = that.createWidget(that.widgets[id], 'show-item');
|
||||
wrap.find('.productParams').filter(':first').find('td').filter(':first').prepend(widget);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
var widget = new ckWidget(jQuery);
|
||||
widget.initList('listing');
|
||||
|
||||
|
||||
$j(function(){
|
||||
$j('.seoTxtContainer').click(function(e) {
|
||||
var el = $j(this),
|
||||
curHeight = el.height(),
|
||||
autoHeight = el.css('height', 'auto').height();
|
||||
|
||||
if(el.hasClass('seoBoxExpanded') === false){
|
||||
el.height(curHeight).animate({
|
||||
height: autoHeight
|
||||
}, "slow" );
|
||||
el.addClass('seoBoxExpanded');
|
||||
}else{
|
||||
el.height(autoHeight).animate({
|
||||
height: "240px"
|
||||
}, "slow" );
|
||||
el.removeClass('seoBoxExpanded');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
(function ($) {
|
||||
var fsHelptipContent = '<a href="https://web.archive.org/web/20120904144913/http://uslugi.allegro.pl/wg/" target="_blank">Wysyłka Gratis</a> to co najmniej jedna darmowa opcja dostawy zakupionego przedmiotu. W ten sposób wygodniej dokonasz transakcji. Bez dodatkowych kosztów!',
|
||||
asHelptipContent = '<a href="https://web.archive.org/web/20120904144913/http://uslugi.allegro.pl/sa/" target="_blank">Standard Allegro</a> to gwarancja udanej transakcji. Oznacza najwyższą jakość obsługi klienta. O wyróżnieniu oferty w ten sposób decydują nasze określone kryteria oraz opinie kupujących.';
|
||||
|
||||
if (fsHelptipContent !== '') {
|
||||
$('.itemFS')
|
||||
.addClass('cursorHelp')
|
||||
.helptip({
|
||||
event: 'hover',
|
||||
hoverDelay: 250,
|
||||
pos: 't',
|
||||
closeClick: true,
|
||||
body: fsHelptipContent
|
||||
});
|
||||
}
|
||||
if (asHelptipContent !== '') {
|
||||
$('span.itemAS')
|
||||
.addClass('cursorHelp')
|
||||
.helptip({
|
||||
event: 'hover',
|
||||
hoverDelay: 250,
|
||||
pos: 't',
|
||||
closeClick: true,
|
||||
body: asHelptipContent
|
||||
});
|
||||
$('span.siIcoAS')
|
||||
.addClass('cursorHelp')
|
||||
.helptip({
|
||||
event: 'hover',
|
||||
hoverDelay: 250,
|
||||
pos: 't',
|
||||
closeClick: true,
|
||||
body: asHelptipContent
|
||||
});
|
||||
}
|
||||
})(jQuery);
|
||||
|
||||
$j("a[rel=external]").attr("target","_blank");
|
||||
if(typeof ado!=="object"){ado={};ado.config=ado.preview=ado.placement=ado.master=ado.slave=function(){};}
|
||||
ado.config({mode: "new", xml: false, characterEncoding: true});
|
||||
|
||||
</script> </body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,34 @@
|
|||
#!/bin/bash
|
||||
domainprefix='https://megumin.tech/boards'
|
||||
|
||||
meta[title]='bashchan'
|
||||
meta[css]='style.css'
|
||||
source templates/head.sh
|
||||
|
||||
echo "<body>
|
||||
<div class='center'>
|
||||
<a href='./'><img id='branding' src='/img/branding_chinacat.png'><br>
|
||||
bashchan</a> - a place for all your shitposts
|
||||
</div>
|
||||
"
|
||||
IFS=$'\n'
|
||||
for i in $(ls -t storage/threads); do
|
||||
IFS=':'
|
||||
array=($(cat storage/threads/$i | head -n 1))
|
||||
echo "<a href='thread.shs?id=$i' class='nolinkdecoration'><div class='post'>"
|
||||
if [[ ${array[1]} != '' ]]; then
|
||||
echo "<span class='thread_title'>${array[1]}</span> | "
|
||||
fi
|
||||
echo "<span class='poster'>${array[0]}</span><br><img src='$domainprefix/i/${array[3]}' class='pic'>${array[2]}</div></a><hr>"
|
||||
done
|
||||
|
||||
|
||||
echo "<div class='center'><h2>Submit a new thread</h2>
|
||||
<form enctype='multipart/form-data' action='post.shs' method='post' id='post'>
|
||||
<input type='hidden' name='rel' value='new'>
|
||||
<input type='hidden' name='a' value='broken'>
|
||||
<input type='text' name='title' class='title' placeholder='Title' required><br>
|
||||
<textarea name='msg' class='msg' placeholder='Message'></textarea><br>
|
||||
<input type='file' name='file' class='file' accept='image/*'>
|
||||
<input type='submit' value='Submit' class='submit'>
|
||||
</form></center>"
|
|
@ -0,0 +1,48 @@
|
|||
#!/bin/bash
|
||||
|
||||
title=$(cat ${post_multipart[2]} | sed -s 's/<//g;s/://g' | tr -d '\n\r')
|
||||
msg=$(cat ${post_multipart[3]} | sed -E 's/<//g;s/$/<br>/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/<//g;s/\r//g')
|
||||
|
||||
if [[ $title == '' && $rel == '' ]]; then
|
||||
echo "Empty title?"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ $(file --mime-type -b $img) == "image/"* ]]; then
|
||||
mv "$img" "$pwd/i/$img_name"
|
||||
img_copied_url="i/$img_name"
|
||||
elif [[ $rel == 'new' ]]; then
|
||||
echo "No image?"
|
||||
return 1
|
||||
elif [[ $msg == '<br>' ]]; 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.<br>
|
||||
<a href='thread.shs?id=$rel'>Click here if you're not redirected</a>"
|
|
@ -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;
|
||||
}
|
|
@ -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 "<body>
|
||||
<div class='center'>
|
||||
<a href='./'><img id='branding' src='/img/branding_chinacat.png'><br>
|
||||
bashchan</a> - a place for all your shitposts
|
||||
</div>
|
||||
"
|
||||
|
||||
IFS=$'\n'
|
||||
for i in $(cat storage/threads/$id); do
|
||||
IFS=':'
|
||||
array=($i)
|
||||
echo "<div class='post'>"
|
||||
if [[ ${array[1]} != '' ]]; then
|
||||
echo "<span class='thread_title'>${array[1]}</span> | "
|
||||
fi
|
||||
echo "<span class='poster'>${array[0]}</span><br>"
|
||||
if [[ -a "$pwd/i/${array[3]}" ]]; then
|
||||
echo "<a href='$domainprefix/i/${array[3]}'><img src='$domainprefix/i/${array[3]}' class='pic'></a>"
|
||||
fi
|
||||
echo "${array[2]}</div>"
|
||||
done
|
||||
|
||||
|
||||
echo "<form enctype='multipart/form-data' action='post.shs' method='post' id='post'>
|
||||
<input type='hidden' name='rel' value='$id'>
|
||||
<input type='hidden' name='a' value='broken'>
|
||||
<input type='text' name='title' class='title' placeholder='Title'><br>
|
||||
<textarea name='msg' class='msg' placeholder='Message'></textarea><br>
|
||||
<input type='file' name='file' class='file' accept='image/*'>
|
||||
<input type='submit' value='Submit' class='submit'>
|
||||
</form>
|
||||
"
|
Binary file not shown.
After Width: | Height: | Size: 7.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
|
@ -0,0 +1,65 @@
|
|||
#!/bin/bash
|
||||
|
||||
meta[title]='HTTP.sh'
|
||||
meta[author]='Dominika, Laura, Patrycja'
|
||||
meta[description]='HTTP.sh - a quick and dirty webserver, written in Bash'
|
||||
meta[keywords]='bash,http,web,server,http.sh'
|
||||
meta[lang]='en'
|
||||
|
||||
source templates/head.sh
|
||||
|
||||
echo "<body>
|
||||
<style>
|
||||
h1,h2,h3 {
|
||||
color: #fff
|
||||
}
|
||||
.lr {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
}
|
||||
</style>"
|
||||
if [[ ! ${cookies[sh_session]} ]]; then
|
||||
echo "<div class='lr'><a href='login.shs'>Log in</a> or <a href='register.shs'>Register</a></div>"
|
||||
else
|
||||
echo "<div class='lr'>Logged in as ${cookies[username]}| <a href='logout.shs'>Log out</a></div>"
|
||||
fi
|
||||
echo "<img src='img/branding_pxplus.png'>
|
||||
<h2>HTTP.sh - a quick and dirty webserver, written in Bash</h2>
|
||||
|
||||
<p>
|
||||
Although we've seen several attempts to create a Bash web framework, all of them fell flat one way or another.<br>
|
||||
We've decided to change that. Did we succeed? You be the judge!
|
||||
</p>
|
||||
|
||||
<h3>Download</h3>
|
||||
<p>
|
||||
This web server was tested as much as the time allowed, but we can't say for certain that it's bug free.<br>
|
||||
If you want to check out our (dirty) code, download the current <a href='http://f.sakamoto.pl/httpsh.tar.xz'>tarball</a>.<br><br>
|
||||
We also can't guarantee that HTTP.sh is <a href='https://xkcd.com/641/'>asbestos free</a>, so <b>proceed with caution.</b>
|
||||
</p>
|
||||
|
||||
<h3>Dependencies</h3>
|
||||
<ol>
|
||||
<li>Bash or 100% compatible shell</li>
|
||||
<li><a href='http://nmap.org/ncat'>Ncat</a> - nc/nc.traditional WILL NOT work</li>
|
||||
<li>GNU coreutils (dd, base64 and others)</li>
|
||||
<li>pkill</li>
|
||||
<li>mktemp</li>
|
||||
<li>sha1sum, sha256sum</li>
|
||||
<li>curl (only for a few demos)</li>
|
||||
<li>certbot (only if you'd like to get a SSL cert)
|
||||
</ol>
|
||||
|
||||
<h3>Demos</h3>
|
||||
<ol>
|
||||
<li><a href='boards/'>bashchan</a> (an imageboard)</li>
|
||||
<li><a href='pastebin/'>bashbin</a> (a pastebin)</li>
|
||||
<li><a href='yt/'>bashtube</a> (a YouTube frontend)</li>
|
||||
<li><a href='shortener/'>bashurl</a> (a URL shortener)</li>
|
||||
<li><a href='upload/'>bashupload</a> (a file uploader)</li>
|
||||
<li><a href='allegro/'>bashallgero</a> (a frontend for a Polish auction site)</li>
|
||||
<li><a href='img/'>listing</a> (just a file listing, but it looks mighty cool)</li>
|
||||
</ol>
|
||||
|
||||
<hr>
|
||||
Made by <a href='https://sakamoto.pl/' id='reds'>reds</a>, <a href='https://selfisekai.rocks/' style='color:#d60270;'>selfisekai</a> and <a href='https://ptrcnull.me/' style='color:#ffb9d3'>ptrcnull</a>. IF YOU LOG IN, THIS SITE WILL STORE COOKIES ON YOUR PERSONAL COMPUTING DEVICE"
|
|
@ -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/<//g;s/___/?/')"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
source templates/head.sh
|
||||
|
||||
if [[ $status == 1 && $reason != '' ]]; then
|
||||
echo $reason
|
||||
fi
|
||||
|
||||
echo "<h1>Log in...</h1>
|
||||
<form method='post'>
|
||||
<label for='login'>Login:</label>
|
||||
<input type='text' name='login'><br>
|
||||
<label for='password'>Password:</label>
|
||||
<input type='password' name='password'><br>
|
||||
<input type='submit' value='Login'>
|
||||
</form>
|
||||
(please make sure that you're connecting over SSL)"
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
logout
|
||||
meta[redirect]='/'
|
||||
source templates/head.sh
|
||||
|
||||
echo "Logged out successully. Redirecting.."
|
|
@ -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 "<body>
|
||||
|
||||
<form method='post'>
|
||||
<input type='submit' value='Send!'>
|
||||
<input type='checkbox' name='public'>
|
||||
<label for='public'>Public?</label><br>
|
||||
<textarea name='paste' rows='25' cols='80'></textarea>
|
||||
</form>
|
||||
"
|
||||
|
||||
if session_verify ${cookies[sh_session]}; then
|
||||
echo "<h3>Your pastes:</h3>"
|
||||
pastes=$(grep -E "$(session_get_username ${cookies[sh_session]})\$" storage/pastes)
|
||||
if [[ $pastes != '' ]]; then
|
||||
echo "<ol>"
|
||||
for i in $pastes; do
|
||||
IFS=':'
|
||||
array=($i)
|
||||
echo "<li><a href='${array[0]}'>${array[0]}</a></li>"
|
||||
done
|
||||
echo "</ol>"
|
||||
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 "<h3>Latest public pastes:</h3><ol>"
|
||||
public=$(tac $pwd/list | head -n 10)
|
||||
|
||||
IFS=$'\n'
|
||||
for i in $public; do
|
||||
echo "<li><a href='$domainprefix$i'>$i</a></li>"
|
||||
done
|
||||
unset IFS
|
||||
echo "</li>"
|
||||
|
|
@ -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 "<h1>Register</h1>
|
||||
<form method='post'>
|
||||
<label for='login'>Login:</label>
|
||||
<input type='text' name='login'><br>
|
||||
<label for='password'>Password:</label>
|
||||
<input type='password' name='password'><br>
|
||||
<input type='submit' value='Register'>
|
||||
</form>
|
||||
(please make sure that you're connecting over SSL)"
|
|
@ -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 "<h1>ID not found</h1>"
|
||||
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 "<p>URL created: <a href='$domainprefix?u=$id'>link</a></p>"
|
||||
else
|
||||
echo '<h1>Revolutionary URL shortener</h1>
|
||||
<form method="POST">
|
||||
<input type="text" name="url" placeholder="URL">
|
||||
<button type="submit">Submit</button>
|
||||
</form>';
|
||||
fi
|
||||
fi
|
|
@ -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 "<a href='$domainprefix$relative'>Your uploaded file</a>"
|
||||
done
|
||||
else
|
||||
echo '<form enctype="multipart/form-data" method="POST">
|
||||
<input name="uploadedfile" type="file" /><br />
|
||||
<input type="submit" value="Upload File" />
|
||||
</form>'
|
||||
fi
|
|
@ -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 "<a href='./'><--- back to main</a><br><h1>Your favourites</h1>"
|
||||
|
||||
IFS=$'\n'
|
||||
for i in $(tac storage/faves); do
|
||||
IFS=':'
|
||||
array=($i)
|
||||
echo "<div><a href='watch.shs?v=${array[1]}'><img src='https://i.ytimg.com/vi/${array[1]}/mqdefault.jpg'><br><b>${array[@]:2:999}</b></a><br></div>";
|
||||
done
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash
|
||||
source templates/head.sh
|
||||
|
||||
echo "<form action='${r[url]}/search.shs'>
|
||||
<input name='q' type='text'>
|
||||
<input type='submit' value='Search'>
|
||||
</form>
|
||||
|
||||
<h1>All user's favourites</h1>"
|
||||
|
||||
IFS=$'\n'
|
||||
for i in $(tac storage/faves); do
|
||||
IFS=':'
|
||||
array=($i)
|
||||
echo "<div><a href='watch.shs?v=${array[1]}'><img src='https://i.ytimg.com/vi/${array[1]}/mqdefault.jpg'><br><b>${array[@]:2:999}</b></a><br>Favourited by ${array[0]}</div>";
|
||||
done
|
|
@ -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 "<form action='${r[url]}/search.shs'>
|
||||
<input name='q' type='text'>
|
||||
<input type='submit' value='Search'>
|
||||
</form>
|
||||
"
|
||||
|
||||
if [[ ${get_data[q]} ]]; then
|
||||
query=${get_data[q]}
|
||||
query_nice=$(echo ${get_data[q]} | sed -s 's/+/ /g')
|
||||
|
||||
echo "<p>Searching for '$query_nice'</p>"
|
||||
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 "<a href='/yt/watch.shs?v=${id[$i]}'><img src='https://i.ytimg.com/vi/${id[$i]}/mqdefault.jpg'><br>${title[$i]}</a><br>"
|
||||
done
|
||||
else
|
||||
echo "search for something will 'ya?"
|
||||
fi
|
|
@ -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
|
|
@ -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 "<div><img src='http://i.ytimg.com/vi/$i/hqdefault.jpg'><br><audio src='$(youtube-dl -g -f 251 $i)' controls></audio></div>";
|
||||
#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 "<form action='search.shs'>
|
||||
<input name='q' type='text'>
|
||||
<input type='submit' value='Search'>
|
||||
</form>
|
||||
<div><br><video src='$url' controls></video>
|
||||
<h2>$title</h2>
|
||||
<div>
|
||||
<div>
|
||||
Uploaded by <b><a href='$(echo $video | jq -r '.uploader_url')'>$(echo $video | jq -r '.uploader')</a></b> on <b>$(date -d "$(echo $video | jq -r '.upload_date')" "+%d %B %Y")</b>
|
||||
</div>
|
||||
<div>
|
||||
<b>$(echo $video | jq -r '.view_count')</b> views<br>
|
||||
<b>$(echo $video | jq -r '.like_count')</b> likes, <b>$(echo $video | jq -r '.dislike_count')</b> dislikes.<br>"
|
||||
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 "<a href='fav.shs?v=$(echo ${get_data[v]} | sed -s 's/<//g;')' target='_blank'>Add to favourites</a><br>"
|
||||
else
|
||||
echo "<a href='unfav.shs?v=$(echo ${get_data[v]} | sed -s 's/<//g;')' target='_blank'>Remove from favourites</a><br>"
|
||||
fi
|
||||
else
|
||||
echo "<b><a href='/login.shs?r=$(echo ${r[url]} | sed -s 's/?/___/')'>Log in</a> to add this video to your favourites!</b><br>"
|
||||
fi
|
||||
echo "<br><br>
|
||||
</div>
|
||||
</div>
|
||||
<span><i>Description</i>:<br>$(echo $video | jq -r '.description' | sed -E 's/$/<br>/g')</span>
|
||||
</div>";
|
||||
else
|
||||
source templates/head.sh
|
||||
echo "pls add ?v param i'm still WiP"
|
||||
fi
|
Loading…
Reference in New Issue