From fadb9d36565c0349faeafdc773ed81868d2d52e1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Paul=20H=C3=A4nsch?= Date: Fri, 19 Mar 2021 13:36:49 +0100 Subject: [PATCH] working framework --- index.cgi | 106 ++++++++++++++++++++++++++++++++++++++++++++++++ session_lock.sh | 60 +++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100755 index.cgi create mode 100644 session_lock.sh diff --git a/index.cgi b/index.cgi new file mode 100755 index 0000000..04128e4 --- /dev/null +++ b/index.cgi @@ -0,0 +1,106 @@ +#!/bin/sh + +_EXEC="${_EXEC:-.}" +_DATA="${_DATA:-.}" + +. "$_EXEC"/cgilite/cgilite.sh +. "$_EXEC"/cgilite/session.sh +. "$_EXEC"/cgilite/file.sh +. "$_EXEC"/session_lock.sh + +yield_page(){ + page="$1" + printf '%s\r\n' 'Content-Type: text/html; charset=utf-8' \ + "Content-Security-Policy: script-src 'none'" \ + '' + { printf '[html + [head + [meta name="viewport" content="width=device-width"] + [link rel="stylesheet" type="text/css" href="common.css"] + [link rel="stylesheet" type="text/css" href="webnote.css"] + [title Webnote] + ] [body class="%s" + ' "$page" + cat + printf '] ]' + } |"$_EXEC/cgilite/html-sh.sed" -u +} + +case ${PATH_INFO##*/} in + favicon.ico) printf '%s\r\n' 'Content-Length: 0' '';; + common.css) FILE "$_EXEC/cgilite/common.css";; + webnote.css) FILE "$_EXEC/webnote.css";; + '') yield_page <<-EOF + [form .new action=new [button type=submit New Note] + [ul .recent + $({ COOKIE pages; echo; } |tr \ \\n |while read page; do + [ "$(printf %s "$page" |checkid)" ] && printf '[li [a href="./%s" . %s]]' "$page" "$page" + done)] + ] + EOF + return 0 + ;; + new) + newid="$(timeid)" + touch "$_DATA/$newid" + REDIRECT "./$newid" + ;; +esac + +doc="$_DATA/$(printf %s ${PATH_INFO##*/} |checkid)" + +if [ ! -f "$doc" ]; then + REDIRECT "${PATH_INFO%%/*}/" + return 0 +fi + +[ $REQUEST_METHOD = POST ] && case $(POST action) in + edit) + if temp=$(SLOCK "$doc"); then + yield_page <<-EOF + [form method=POST + [input type=hidden name=session_key value="$SESSION_KEY"] + [button type=submit name=action value=cancel Cancel] + [button type=submit name=action value=update Update] + [textarea name=document . $(HTML <"$doc")] + ] + EOF + else + yield_page <<-EOF + [p .error .locked Someone else is already editing this Dokument. Wait a few minutes and try again. [a href="$PATH_INFO" Nothing else I can do.]] + EOF + fi + return 0 + ;; + cancel) + RELEASE_SLOCK "$doc" + REDIRECT "$PATH_INFO" + ;; + update) + if temp=$(CHECK_SLOCK "$doc"); then + RELEASE_SLOCK "$doc" + POST document >"${doc}" + REDIRECT "$PATH_INFO" + else + yield_page <<-EOF + [p .error .stolen Your edit took too long and someone else is now editing this file. [a href="$PATH_INFO" Dang, I must be quicker next time!]] + [p Copy your Content for reference:] + [div .text . $(POST document |HTML)] + EOF + fi + return 0 + ;; +esac + +COOKIE pages |tr \ \\n |grep -qF "${doc##*/}" \ +|| SET_COOKIE +$((90 * 86400)) pages="$(COOKIE pages && printf ' %s' "${doc##*/}" || printf '%s' "${doc##*/}")" + +yield_page <<-EOF + [form method=POST + [input type=hidden name=session_key value="$SESSION_KEY"] + [button type=submit name=action value=edit Edit] + ] + [div .text + $(HTML <"$doc") + ] + EOF diff --git a/session_lock.sh b/session_lock.sh new file mode 100644 index 0000000..de1641a --- /dev/null +++ b/session_lock.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +[ "$include_session_lock" ] && return 0 +include_session_lock="$0" + +SLOCK(){ + local file="$1"; + local timeout="${2-900}" + local lockdir="$_DATA/lock/${file#$_DATA}"; lockdir="${lockdir%/}" + local ovlock="${lockdir%/*}/delete.${lockdir##*/}" + local tempfile="$lockdir/${SESSION_ID}" + local lockexpire=$(( $(date +%s) - timeout )) + + mkdir -p "${lockdir%/*}" + + if [ -e "$lockdir" ] \ + && [ "$(stat -c %Y "$lockdir")" -lt "$lockexpire" ] \ + && mkdir "$ovlock"; then + [ "$(stat -c %Y "$lockdir")" -lt "$lockexpire" ] \ + && rm -r "$lockdir" + rmdir "$ovlock" + fi + + printf '%s\n' "$tempfile" + if mkdir "$lockdir" 2>&-; then + cp "$file" "$tempfile" + return 0 + else + return 1 + fi +} + +CHECK_SLOCK(){ + local file="$1"; + local lockdir="$_DATA/lock/${file#$_DATA}"; lockdir="${lockdir%/}" + local tempfile="$lockdir/${SESSION_ID}" + + printf '%s\n' "$tempfile" + if [ -f "$tempfile" ]; then + touch "$lockdir" + return 0 + else + return 1 + fi +} + +RELEASE_SLOCK(){ + local file="$1"; + local lockdir="$_DATA/lock/${file#$_DATA}"; lockdir="${lockdir%/}" + local ovlock="${lockdir%/*}/delete.${lockdir##*/}" + local tempfile="$lockdir/${SESSION_ID}" + + if [ -f "$tempfile" ] && mkdir "$ovlock"; then + [ -f "$tempfile" ] && rm -r "$lockdir" + rmdir "$ovlock" + return 0 + else + return 1 + fi +} -- 2.39.2