From: Paul Hänsch Date: Wed, 29 Sep 2021 11:09:40 +0000 (+0200) Subject: Merge commit 'b5943a26698776a9814850ed2356eda5076fa00a' X-Git-Url: https://git.plutz.net/?a=commitdiff_plain;h=3820e27ad1d4e9c9407c7cc316a016c80ee79902;hp=b5943a26698776a9814850ed2356eda5076fa00a;p=rawnet Merge commit 'b5943a26698776a9814850ed2356eda5076fa00a' --- diff --git a/.gitignore b/.gitignore index 5c9950a..e3c57b4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -cgilite -serverkey +channels.db users.db +serverkey diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..24781a9 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +.PHONY: _subtrees + +_subtrees: _cgilite + +cgilite: + git subtree add --squash -P $@ https://git.plutz.net/git/$@ master + +_cgilite: cgilite + git subtree pull --squash -P $< https://git.plutz.net/git/$< master diff --git a/cgilite/.gitignore b/cgilite/.gitignore new file mode 100644 index 0000000..5c9950a --- /dev/null +++ b/cgilite/.gitignore @@ -0,0 +1,3 @@ +cgilite +serverkey +users.db diff --git a/cgilite.sh b/cgilite/cgilite.sh similarity index 100% rename from cgilite.sh rename to cgilite/cgilite.sh diff --git a/common.css b/cgilite/common.css similarity index 100% rename from common.css rename to cgilite/common.css diff --git a/file.sh b/cgilite/file.sh similarity index 100% rename from file.sh rename to cgilite/file.sh diff --git a/html-sh.sed b/cgilite/html-sh.sed similarity index 100% rename from html-sh.sed rename to cgilite/html-sh.sed diff --git a/logging.sh b/cgilite/logging.sh similarity index 100% rename from logging.sh rename to cgilite/logging.sh diff --git a/markdown.awk b/cgilite/markdown.awk similarity index 100% rename from markdown.awk rename to cgilite/markdown.awk diff --git a/session.sh b/cgilite/session.sh similarity index 100% rename from session.sh rename to cgilite/session.sh diff --git a/storage.sh b/cgilite/storage.sh similarity index 100% rename from storage.sh rename to cgilite/storage.sh diff --git a/users.sh b/cgilite/users.sh similarity index 100% rename from users.sh rename to cgilite/users.sh diff --git a/index.cgi b/index.cgi new file mode 100755 index 0000000..1a8914d --- /dev/null +++ b/index.cgi @@ -0,0 +1,77 @@ +#!/bin/sh + +USER_REQUIREEMAIL=false + +. "${_EXEC:-${0%/*}}"/cgilite/cgilite.sh +. "$_EXEC"/cgilite/session.sh nocookie +. "$_EXEC"/cgilite/users.sh + +PATH_INFO="$(PATH "/${PATH_INFO#${_BASE}}")" + +export MD_HTML="false" +if [ "$(which awk)" ]; then + markdown() { awk -f "$_EXEC/cgilite/markdown.awk"; } +else + markdown() { busybox awk -f "$_EXEC/cgilite/markdown.awk"; } +fi + +yield_page(){ + title="${1:-RAW:NET}" page="$2" + printf '%s\r\n' 'Content-Type: text/html; charset=utf-8' \ + "Content-Security-Policy: script-src 'none'" \ + '' + { cat <<-EOF + [!DOCTYPE HTML] + [html [head + [meta name="viewport" content="width=device-width"] + [link rel="stylesheet" type="text/css" href="$_BASE/cgilite/common.css"] + [link rel="stylesheet" type="text/css" href="$_BASE/rawnet.css"] + [title . $(HTML "$title")] + ] [body class="$page" + [header + [form method=POST action="$_BASE/search/" + [input name=search placeholder="Search"] + ] + $( [ ! "$USER_ID" ] \ + && printf '[div #user_login [a href="%s/login/" Login]]' "$_BASE" \ + || w_user_login + ) + ][main + EOF + cat + printf ']]]' + } |"$_EXEC/cgilite/html-sh.sed" -u +} + +case ${PATH_INFO} in + /favicon.ico) printf '%s\r\n' 'Content-Length: 0' '';; + *.css) + . "${_EXEC}/cgilite/file.sh" + FILE "${_EXEC}/${PATH_INFO}" + ;; + /login/) + if [ "$USER_ID" ]; then + REDIRECT "${_BASE}/" + else + yield_page 'RAW:NET Login' login <<-EOF + $(w_user_login) + EOF + fi + ;; + /register/) + yield_page 'RAW:NET Register User' register <<-EOF + $(w_user_register) + EOF + ;; + /recover/) + yield_page 'RAW:NET Recover Account' recover <<-EOF + $(w_user_recover) + EOF + ;; + /|/channel/*) . "${_EXEC}/page_channel.sh";; + /playlist/*) . "${_EXEC}/page_playlist.sh";; + /search/*) . "${_EXEC}/page_search.sh";; + *) . "${_EXEC}/page_404.sh";; +esac + +exit 0 diff --git a/page_404.sh b/page_404.sh new file mode 100755 index 0000000..a4acce8 --- /dev/null +++ b/page_404.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +printf 'Status: 404 Not Found\r\n' + +yield_page '' 404 <<-EOF +[h1 404][p +[span Page not found or nevermore] +[span Quoth the server: 404] +] +EOF diff --git a/page_channel.sh b/page_channel.sh new file mode 100755 index 0000000..d12f417 --- /dev/null +++ b/page_channel.sh @@ -0,0 +1,183 @@ +#!/bin/sh + +chan_db="$_DATA/channels.db" + +channel='' video='' action='' +path_info="$PATH_INFO" +path_info="${path_info#/channel/}" +if [ "$(checkid "${path_info%%/*}")" ]; then + channel="${path_info%%/*}" + path_info="${path_info#*/}" +fi +if [ "$(checkid "${path_info%%/*}")" ]; then + video="${path_info%%/*}" + path_info="${path_info#*/}" +fi +action="${path_info}" +unset path_info + +# Channel +# ID NAME DESCRIPTION LOGO THEME AUTHORS DESCR_CACHE FUTUREUSE + +if [ "$channel" -a -f "$chan_db" -a -r "$chan_db" ]; then + read -r CHANNEL_ID CHANNEL_NAME CHANNEL_DESCRIPTION CHANNEL_LOGO \ + CHANNEL_THEME CHANNEL_AUTHORS CHANNEL_DESCR_CACHE \ + CHANNEL_FUTUREUSE <<-EOF + $(grep "^${channel} " "${chan_db}") + EOF + if [ "$CHANNEL_ID" ]; then + CHANNEL_NAME="$(UNSTRING "${CHANNEL_NAME}")" + CHANNEL_DESCRIPTION="$(UNSTRING "$CHANNEL_DESCRIPTION")" + CHANNEL_AUTHORS="$(UNSTRING "$CHANNEL_AUTHORS")" + CHANNEL_DESCR_CACHE="$(UNSTRING "$CHANNEL_DESCR_CACHE")" + vid_db="${_DATA}/${CHANNEL_ID}/videos.db" + else + channel='' + fi +fi + +update_channel(){ + local id="${1}" name="${2}" description="${3}" logo="${4}" theme="${5}" \ + authors="${6}" descr_cache="${7}" futureuse="${8}" + local ID INFO + if LOCK "$chan_db"; then + while read -r ID INFO; do + if [ "$id" = "$ID" ]; then + printf '%s %s %s %s %s %s %s %s\n' \ + "$id" "$(STRING "$name")" "$(STRING "$description")" \ + "${logo:-\\}" "${theme:-\\}" "$(STRING "$authors")" \ + "$(printf %s "$description" |markdown |STRING)" \ + "${futureuse:-\\}" + else + printf '%s %s\n' "$ID" "$INFO" + fi + done <"$chan_db" >"${chan_db}.$$" + mv -- "${chan_db}.$$" "${chan_db}" + RELEASE "$chan_db" + else + return 1 + fi +} + +# Video +# ID NAME DESCRIPTION RESX RESY LENGTH COVER STATUS UPLOADER HITS + +[ "$REQUEST_METHOD" = POST ] && case "$(POST action)" in + newchannel) + channel="$(POST channel |checkid)" + if [ ! "$USER_ID" ]; then + REDIRECT "${_BASE}/channel/#ERROR_NEWCHANNEL_NOTALLOWED" + elif LOCK "$chan_db"; then + if grep -q '^${channel} ' "$chan_db"; then + RELEASE "$chan_db" + REDIRECT "${_BASE}/channel/#ERROR_NEWCHANNEL_EXISTS" + else + printf '%s \\ \\ \\ \\ %s \\ \\\n' \ + "$channel" "$(STRING "$USER_ID")" \ + >>"$chan_db" + RELEASE "$chan_db" + REDIRECT "${_BASE}/channel/${channel}/edit" + fi + else + REDIRECT "${_BASE}/channel/#ERROR_NEWCHANNEL_NOLOCK" + fi + ;; + update_channel) + if [ ! "$channel" ]; then + REDIRECT "${_BASE}/channel/#ERROR_NOCHANNEL" + elif [ ! "$USER_ID" ]; then + REDIRECT "${_BASE}/channel/${channel}/#ERROR_NOTLOGGEDIN" + elif [ "${CHANNEL_AUTHORS##*${USER_ID}*}" ]; then + REDIRECT "${_BASE}/channel/${channel}/#ERROR_UPDATE_NOTALLOWED" + elif update_channel "$channel" "$(POST name)" "$(POST description)" \ + "" "" "$USER_ID" "" ""; then + REDIRECT "${_BASE}/channel/${channel}/" + else + REDIRECT "${_BASE}/channel/${channel}/#ERROR_UPDATE_NOLOCK" + fi + ;; + newvideo) + video="$(POST video |checkid)" + # database video create + REDIRECT "${_BASE}/channel/${channel}/${video}/" + ;; +esac + +w_video(){ + local CID="$1" thumb + local ID NAME DESCRIPTION RESX RESY LENGTH COVER STATUS UPLOADER HITS FUTUREUSE + if read -r ID NAME DESCRIPTION RESX RESY LENGTH COVER STATUS UPLOADER HITS FUTUREUSE; then + thumb="${_BASE}/${CID}/thumb_${ID}.jpg" + cat <<-EOF + [div .video + [h3 . $(UNSTRING "$NAME" |HTML)] + [img href="${thumb}" alt="$(UNSTRING "$DESCRIPTION" |HTML)"] + ] + EOF + else + return 1 + fi +} + +w_channel(){ + local vid_db + local ID NAME DESCRIPTION LOGO THEME AUTHORS DESCR_CACHE FUTUREUSE + if read -r ID NAME DESCRIPTION LOGO THEME AUTHORS DESCR_CACHE FUTUREUSE; then + vid_db="${_DATA}/${ID}/videos.db" + [ "$NAME" = \\ ] && NAME="(UNNAMED CHANNEL)" + cat <<-EOF + [div .channel + [h2 [a href="${_BASE}/channel/${ID}/" $(UNSTRING "${NAME}" |HTML)]] + [div .description . $(UNSTRING "$DESCR_CACHE")] + $( [ -f "$vid_db" -a -r "$vid_db" ] \ + && while w_video "$ID"; do :; done <"$vid_db" + ) + ] + EOF + else + return 1 + fi +} + +w_channel_list(){ + if [ $USER_ID ]; then + printf ' + [form .channel .newchannel method=POST + [hidden "channel" "%s"] + [submit "action" "newchannel" New Channel] + ]' "$(timeid)" + fi + [ -f "$chan_db" -a -r "$chan_db" ] \ + && while w_channel; do :; done <"$chan_db" +} + +if [ "$channel" -a "$video" ]; then + . ${_EXEC}/page_video.sh +elif [ "$channel" -a "$action" = edit ]; then + [ "$USER_ID" -a ! "${CHANNEL_AUTHORS##*${USER_ID}*}" ] \ + || REDIRECT "${_BASE}/${channel}/#ERROR_EDIT_NOTALLOWED" + yield_page "$CHANNEL_NAME - Edit" "channel edit" <<-EOF + [form .channel .edit method=POST + [input name="name" value="$(HTML "$CHANNEL_NAME")" placeholder="Channel Name"] + [textarea name="description" placeholder="Description" . $(HTML "$CHANNEL_DESCRIPTION")] + [submit "action" "update_channel" . Update] + ] + EOF +elif [ "$channel" ]; then + yield_page "$CHANNEL_NAME" "channel" <<-EOF + [h1 .name $(HTML "$CHANNEL_NAME")] + $( [ "$USER_ID" -a ! "${CHANNEL_AUTHORS##*${USER_ID}*}" ] \ + && printf '[a href="edit" edit]' + ) + [div .description . ${CHANNEL_DESCR_CACHE}] + [div .videos + $( [ -f "$vid_db" -a -r "$vid_db" ] \ + && while w_video "$ID"; do :; done <"$vid_db" + ) + ] + EOF +else + yield_page "Channels" "channels" <<-EOF + $(w_channel_list) + EOF +fi diff --git a/rawnet.css b/rawnet.css new file mode 100644 index 0000000..93de0da --- /dev/null +++ b/rawnet.css @@ -0,0 +1,64 @@ +body { + background-size: 4pt 4pt; + background-image: /* #6AF #6FF */ + linear-gradient( 0deg, transparent 25%, rgba(128,128,128,.5) 25% 50%, transparent 50% 75%, rgba(192,192,192,.5) 75%), + linear-gradient(90deg, transparent 25%, rgba(128,128,128,.5) 25% 50%, transparent 50% 75%, rgba(192,192,192,.5) 75%); +} + +header { + background-color: rgba(0,0,0,.75); + padding: .25em; + border-bottom: 1pt solid; + box-shadow: #000 0 .25em .5em; + text-align: center; +} +header > * { + display: inline-block; +} + +header #user_login { + float: right; + margin: .125em .5em; +} +header #user_login > p { + display: inline-block; + color: #EEE; + font-size: .875em; line-height: 1.125em; + max-width: 12em; +} + +main { + background-color: rgba(255,255,255,.75); + margin: 1em; padding: 1em; + box-shadow: #000 .125em .125em 1em; +} + +body.channel main h1.name { + text-align: center; +} +body.channel main .description, +body.channel main form.edit.channel { + max-width: 40em; + margin: auto; +} + +body.channel main form.edit.channel input[name=name], +body.channel main form.edit.channel textarea[name=description] { + display: block; + width: 100%; + margin-bottom: .5em; +} + +body.channels main .channel { + border: 1pt solid; + border-radius: 4pt; + padding: .5em; + margin-bottom: .5em; +} + +body.channels main .channel > h2, +body.channels main .channel > .description { + margin: 0; + width: 140pt; + background-color: #FFF; +}