]> git.plutz.net Git - cgilite/blob - session.sh
STRING encodes empty values as backslash for easyer `read`ing of TAB-DBs, UNSTRING...
[cgilite] / session.sh
1 #!/bin/sh
2
3 [ -n "$include_session" ] && return 0
4 include_session="$0"
5
6 _DATE="$(date +%s)"
7 SESSION_TIMEOUT="${SESSION_TIMEOUT:-7200}"
8
9 if ! which uuencode >/dev/null; then
10   uuencode() { busybox uuencode "$@"; }
11 fi
12 if ! which sha256sum >/dev/null; then
13   sha256sum() { busybox sha256sum "$@"; }
14 fi
15
16 if which openssl >/dev/null; then
17   session_mac(){ { [ $# -gt 0 ] && printf %s "$*" || cat; } | openssl dgst -sha1 -hmac "$(server_key)" -binary |slopecode; }
18 else
19   # Gonzo MAC if openssl is unavailable
20   session_mac(){
21     { server_key | dd status=none bs=256 count=1 skip=1
22       { server_key | dd status=none bs=256 count=1
23         [ $# -gt 0 ] && printf %s "$*" || cat
24       } \
25       | sha256sum -;
26     } \
27     | sha256sum | cut -d\  -f1
28   }
29 fi
30
31 server_key(){
32   IDFILE="${IDFILE:-${_DATA:-.}/serverkey}"
33   if [ "$(stat -c %s "$IDFILE")" -ne 512 ] || ! cat "$IDFILE"; then
34     dd count=1 bs=512 if=/dev/urandom \
35     | tee "$IDFILE"
36   fi 2>&-
37 }
38
39 slopecode(){
40   # 6-Bit Code that retains sort order of input data, while beeing safe to use
41   # in ascii transmissions, unix file names, HTTP URLs, and HTML attributes
42
43   { [ $# -gt 0 ] && printf %s "$*" || cat; } \
44   | uuencode -m - | sed '
45     1d;$d; 
46     y;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/;0123456789:=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz;
47   '
48 }
49
50 randomid(){
51   dd bs=12 count=1 if=/dev/urandom 2>&- \
52   | slopecode
53 }
54
55 timeid(){
56   d=$(($_DATE % 4294967296))
57   { printf "$(
58       printf \\%o \
59         $((d / 16777216 % 256)) \
60         $((d / 65536 % 256)) \
61         $((d / 256 % 256)) \
62         $((d % 256))
63     )"
64     dd bs=8 count=1 if=/dev/urandom 2>&-
65   } | slopecode
66 }
67
68 transid(){
69   # transaction ID to modify a given file
70   local file="$1"
71   session_mac "$(stat -c %F%i%n%N%s%Y "$file" 2>&-)" "$SESSION_ID"
72 }
73
74 checkid(){ { [ $# -gt 0 ] && printf %s "$*" || cat; } | grep -m 1 -xE '[0-9a-zA-Z:=]{16}'; }
75
76 update_session(){
77   local session sid time sig checksig
78
79   read -r sid time sig <<-END
80         $(POST session_key || COOKIE session)
81         END
82   
83   checksig="$(session_mac "$sid" "$time")"
84   
85   if ! [ "$checksig" = "$sig" \
86     -a "$time" -ge "$_DATE" \
87     -a "$(printf %s "$sid" |checkid)" ] 2>&-
88   then
89     debug "Setting up new session"
90     sid="$(randomid)"
91   fi
92
93   time=$(( $_DATE + $SESSION_TIMEOUT ))
94   sig="$(session_mac "$sid" "$time")"
95   printf %s\\n "${sid} ${time} ${sig}"
96 }
97
98 SESSION_BIND() {
99   # Set tamper-proof authenticated cookie
100   local key="$1" value="$2"
101   SET_COOKIE session "$key"="${value} $(session_mac "$value" "$SESSION_ID")"
102 }
103
104 SESSION_VAR() {
105   # read authenticated cookie
106   # fail if value has been tampered with
107   local key="$1" value sig
108   value="$(COOKIE "$key")"
109   sig="${value##* }" value="${value% *}"
110   if [ "$sig" = "$(session_mac "$value" "$SESSION_ID")" ]; then
111     printf %s\\n "$value"
112   else
113     return 1
114   fi
115 }
116
117 SESSION_KEY="$(update_session)"
118 SET_COOKIE 0 session="$SESSION_KEY" Path=/ SameSite=Strict HttpOnly
119 SESSION_ID="${SESSION_KEY%% *}"