Skip to content

Instantly share code, notes, and snippets.

@colrichie
Last active August 29, 2015 13:56
Show Gist options
  • Save colrichie/9030248 to your computer and use it in GitHub Desktop.
Save colrichie/9030248 to your computer and use it in GitHub Desktop.
MKCOOKIE - HTTP Cookie String Generator
#! /bin/sh
######################################################################
#
# MKCOOKIE - HTTP Cookie String Generator
#
# USAGE: mkcookie [options] [<name>=<value>]
#
# * <name>=<value> : Cookie varriable name and value
# * OPTIONS:
# - -e <expiring_info>
# for expiring date and time setting, You can use one of the following
# "YYYYMMDDHHMMSS" : direct setting of the datetime period.
# "+<n>" : lifetime in seconds from now.
# "YYYYMMDDHHMMSS+<n>" : lifetime in seconds from the datetime.
# (the datetimes is in your timezone)
# - -p <path_name>
# for path restriction
# - -d <domain_name>
# for domain restriction
# - -s <"Y"|"N"|"A">
# for HTTPS(SSL,TLS) restriction
# "Y" is always ON.
# "N" is always OFF.
# "A" is for auto detection (default), with checking the HTTPS
# enviornmnent variable.
# - -h <"Y"|"N">
# for JavaScript restriction (HttpOnly)
# "Y" is HttpOnly ON.
# "N" is HttpOnly OFF (default).
# * NOTE:
# - The cookie string is started with <LF> for more usefulness. If you
# do not want the <LF> on the head, you can write the following.
# > mkcookie name=val | awk 'NR>1'
# - You can give me the cookie data with STDIN instead of the last
# argument. But name and value must be separated with space " "
# instead of equal "=".
#
# Return: $?=0 (when all of the options are valid)
# stdout : HTTP Cookie string
#
# Written by Rich Mikan (richmikan[at]richlab.org) at 2014/06/27
#
######################################################################
# --- initalization --------------------------------------------------
PATH=/usr/bin:/bin
#
print_usage_and_exit () {
cat <<-__USAGE 1>&2
Usage : ${0##*/} [options] [<name>=<value>]
-e <expiring_info> : for expiring date and time setting
"YYYYMMDDHHMMSS" or "+<n>"
or "YYYYMMDDHHMMSS+<n>"
-p <path_name> : for path restriction
-d <domain_name> : for domain restriction
-s <"Y"|"N"|"A"> : for HTTPS(SSL,TLS) restriction
"Y" is always ON.
"N" is always OFF.
"A" is for auto detection (default).
-h <"Y"|"N"> : for JavaScript restriction (HttpOnly)
"Y" is HttpOnly ON.
"N" is HttpOnly OFF (default).
Version : Sat Jun 28 18:51:06 JST 2014
__USAGE
exit 1
}
# --- parse arguments ------------------------------------------------
var=''
eopt=''
popt=''
dopt=''
sopt=''
hopt=''
optmode=''
i=0
for arg in "$@"; do
i=$((i+1))
if [ -z "$optmode" ]; then
case "$arg" in
-[epdsh]*)
ret=$(echo "${arg#-}" |
awk '{opt = substr($0,1,1); #
opt_str = (length($0)>1) ? substr($0,2) : ""; #
printf("%s %s", opt, opt_str); }')
ret1=${ret%% *}
ret2=${ret#* }
if [ "$ret1" = 'e' ]; then
if [ -n "$ret2" ]; then
eopt=$ret2
else
optmode='e'
fi
fi
if [ "$ret1" = 'p' ]; then
if [ -n "$ret2" ]; then
popt=$ret2
else
optmode='p'
fi
fi
if [ "$ret1" = 'd' ]; then
if [ -n "$ret2" ]; then
dopt=$ret2
else
optmode='d'
fi
fi
if [ "$ret1" = 's' ]; then
if [ -n "$ret2" ]; then
sopt=$ret2
else
optmode='s'
fi
fi
if [ "$ret1" = 'h' ]; then
if [ -n "$ret2" ]; then
hopt=$ret2
else
optmode='h'
fi
fi
;;
*)
if printf '%s' "$arg" | grep '^[^;.[:blank:]=]\{1,\}=.*$' >/dev/null; then
var=$arg
else
print_usage_and_exit
fi
;;
esac
elif [ "$optmode" = 'e' ]; then
eopt=$arg
optmode=''
elif [ "$optmode" = 'p' ]; then
popt=$arg
optmode=''
elif [ "$optmode" = 'd' ]; then
dopt=$arg
optmode=''
elif [ "$optmode" = 's' ]; then
sopt=$arg
optmode=''
elif [ "$optmode" = 'h' ]; then
hopt=$arg
optmode=''
else
print_usage_and_exit
fi
done
# --- validate the arguments -----------------------------------------
if [ -n "$var" ]; then
echo "_$var" | grep '^_[^[:blank:]=]\{1,\}=' >/dev/null || print_usage_and_exit
fi
if [ -n "$eopt" ]; then
check=$(echo "_$eopt" |
awk ' #
/^_[0-9]+[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$/ { #
print substr($0,2), 0; #
exit; #
} #
/^_\+[0-9]+$/ { #
print "_", substr($0,3); #
exit; #
} #
/^_[0-9]+[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\+[0-9]+$/ { #
pos = index($0,"+"); #
print substr($0,2,pos-2), substr($0,pos+1); #
exit; #
} #
{ #
print "!"; #
exit; #
}' )
[ "$check" != '!' ] || print_usage_and_exit
datetime=${check% *}
[ "$datetime" = '_' ] && datetime=$(date -u '+%Y%m%d%H%M%S')
lifetime=${check#* }
fi
if [ -n "$popt" ]; then
path=$( printf '%s' "$popt" | tr -d ';\n' )
[ "_$path" = "_$popt" ] || print_usage_and_exit
fi
if [ -n "$dopt" ]; then
domain=$( printf '%s' "$dopt" | tr -Cd 'A-Za-z0-9.-')
[ "_$domain" = "_$dopt" ] || print_usage_and_exit
fi
if [ -n "$sopt" ]; then
secure=$( printf '%s' "$sopt" | tr -Cd 'A-Za-z' )
[ "_$secure" = "_$sopt" ] || print_usage_and_exit
https=$(printf '%s' "${HTTPS:-off}" | tr -Cd 'A-Za-z')
fi
if [ -n "$hopt" ]; then
httponly=$(printf '%s' "$hopt" | tr -Cd 'A-Za-z' )
[ "_$httponly" = "_$hopt" ] || print_usage_and_exit
fi
# --- print the basic part of cookie (with URL encoding) -------------
if [ -n "$var" ]; then #
printf '%s %s\n' "${var%%=*}" "${var#*=}" #
else #
cat #
fi |
env - path="$path" awk ' #
BEGIN { #
# --- prepare #
LF = sprintf("\n"); #
OFS = ""; #
ORS = ""; #
# --- prepare str2url #
for(i= 0;i< 16;i++){c2a[sprintf("%c",i)]=sprintf("%%0%X",i);} #
for( ;i<256;i++){c2a[sprintf("%c",i)]=sprintf("%%%X" ,i);} #
c2a[" "]="+"; #
for(i=48;i< 58;i++){c2a[sprintf("%c",i)]=sprintf("%c",i); } #
for(i=65;i< 91;i++){c2a[sprintf("%c",i)]=sprintf("%c",i); } #
for(i=97;i<123;i++){c2a[sprintf("%c",i)]=sprintf("%c",i); } #
c2a["-"]="-"; c2a["."]="."; c2a["_"]="_"; c2a["~"]="~"; #
# --- make the additional variables #
s = "'"${datetime:-}"'"; #
if (s != "") { addvar = addvar expires_var(s,"'"$lifetime"'"); } #
s = ENVIRON["path"]; #
if (s != "") { addvar = addvar sprintf("; path=%s", s); } #
s = "'"${domain:-}"'"; #
if (s != "") { addvar = addvar sprintf("; domain=%s", s); } #
s = "'"${secure:-AUTO}"'"; #
if (match(s,/^[Yy]/)) { #
addvar = addvar "; Secure"; #
} else if (match(s,/^[Aa]/) && (match("'"$https"'",/^[Oo][Nn]$/))) { #
addvar = addvar "; Secure"; #
} #
if (match("'"$httponly"'",/^[Yy]/)) { addvar = addvar "; HttpOnly"; } #
} #
{ #
pos = index($0," "); #
print LF, "Set-Cookie: "; #
print substr($0,1,pos-1), "=", str2url(substr($0,pos+1)), addvar; #
} #
function str2url(s0, i,s) { #
for(i=1; i<=length(s0); i++){ #
s = s c2a[substr(s0,i,1)]; #
} #
return s; #
} #
function expires_var(datetime, lifetime, ut1,ut2,dt) { #
max_calced_year = 1970; # To remember every days on 1/1 from #
days_on_Jan1st_from_epoch[1970] = 0; # the Epoch which was calculated once #
split("31 0 31 30 31 30 31 31 30 31 30 31", days_of_month); #
split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec",monthname); #
split("Sun Mon Tue Wed Thu Fri Sat",weekname); #
# #
gm = YYYYMMDDhhmmss2unixtime('$(TZ=UTC+0 date '+%Y%m%d%H%M%S')'); #
lo = YYYYMMDDhhmmss2unixtime('$( date '+%Y%m%d%H%M%S')'); #
offset = lo - gm; #
offset -= (offset%2); # calcell the time lag of the two date starting time #
ut1 = YYYYMMDDhhmmss2unixtime(datetime) + offset; #
ut2 = ut1 + lifetime; #
dt = unixtime2YYYYMMDDhhmmss(ut2); #
return sprintf("; expires=%s", rfc850form(dt)); #
} #
function unixtime2YYYYMMDDhhmmss(ut, Y,M,D,h,m,s,t,i,j) { #
# 1) calculate hour,minute,second and number of days from the Epoch #
s = ut % 60; t = int(ut/60); #
m = t % 60; t = int( t/60); #
h = t % 24; #
days_from_epoch = int( t/24); #
# #
# 2) calculate year #
Y = int(days_from_epoch/365.2425)+1970+1; #
if (Y > max_calced_year) { #
i = days_on_Jan1st_from_epoch[max_calced_year]; #
for (j=max_calced_year; j<Y; j++) { #
i += (j%4!=0)?365:(j%100!=0)?366:(j%400!=0)?365:366; #
days_on_Jan1st_from_epoch[j+1] = i; #
} #
max_calced_year = Y; #
} #
for (;;Y--) { #
if (days_from_epoch >= days_on_Jan1st_from_epoch[Y]) { #
break; #
} #
} #
# #
# 3) calculate month,day #
days_of_month[2] = (Y%4!=0)?28:(Y%100!=0)?29:(Y%400!=0)?28:29; #
D = days_from_epoch - days_on_Jan1st_from_epoch[Y] + 1; #
for (M=1; ; M++) { #
if (D > days_of_month[M]) { #
D -= days_of_month[M]; #
} else { #
break; #
} #
} #
# #
return sprintf("%04d%02d%02d%02d%02d%02d",Y,M,D,h,m,s); #
} #
function YYYYMMDDhhmmss2unixtime(YYYYMMDDhhmmss, Y,M,D,h,m,s,l) { #
# 1) seperate the units #
l = length(YYYYMMDDhhmmss); #
Y = substr(YYYYMMDDhhmmss, 1,l-10)*1; #
M = substr(YYYYMMDDhhmmss,l-9, 2)*1; #
D = substr(YYYYMMDDhhmmss,l-7, 2)*1; #
h = substr(YYYYMMDDhhmmss,l-5, 2)*1; #
m = substr(YYYYMMDDhhmmss,l-3, 2)*1; #
s = substr(YYYYMMDDhhmmss,l-1 )*1; #
# #
# 2) validate #
if ((s>60) || (m>59) || (h>23) || (M>12)) {return -1;} #
days_of_month[2] = (Y%4!=0)?28:(Y%100!=0)?29:(Y%400!=0)?28:29; #
if (D > days_of_month[M] ) {return -1;} #
# #
# 3) adjust the value of year and month #
if (M<3) {M+=12; Y--;} #
# #
# 4) calculate unixtime #
return (365*Y+int(Y/4)-int(Y/100)+int(Y/400)+int(306*(M+1)/10)-428+D-719163)*86400+(h*3600)+(m*60)+s;
} #
function rfc850form(YYYYMMDDhhmmss, Y,M,D,h,m,s,l,w,Y2,M2) { #
# 1) seperate the units #
l = length(YYYYMMDDhhmmss); #
Y = substr(YYYYMMDDhhmmss, 1,l-10)*1; #
M = substr(YYYYMMDDhhmmss,l-9, 2)*1; #
D = substr(YYYYMMDDhhmmss,l-7, 2)*1; #
h = substr(YYYYMMDDhhmmss,l-5, 2)*1; #
m = substr(YYYYMMDDhhmmss,l-3, 2)*1; #
s = substr(YYYYMMDDhhmmss,l-1 )*1; #
# 2) choose the weekday #
M2 = (M<3) ? M+12 : M; #
Y2 = (M<3) ? Y-1 : Y; #
w = (365*Y2+int(Y2/4)-int(Y2/100)+int(Y2/400)+int(306*(M2+1)/10)+D-1)%7+1; #
# 3) generate the rfc850 formatted datetime #
return sprintf("%s, %02d-%s-%04d %02d:%02d:%02d GMT", #
weekname[w], D, monthname[M], Y, h, m, s); #
} #
'
# --- finish ---------------------------------------------------------
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment