]> CyberLeo.Net >> Repos - CDN/flag.git/blob - flag
Avoid caching flag if no usable crc32 algo was found
[CDN/flag.git] / flag
1 #!/bin/sh
2
3 #set -x
4
5 # Places for flags:
6 # $HOME/.flag-cache <- Autogenerated flag (refreshed when hostname changes)
7 # /etc/flag <- Site admin's flag
8 # $HOME/.flag <- Local user's flag
9 # Check them in that order.
10
11 hash_string() {
12   # Hash the passed string into 8 hex characters
13   [ -z "${crc32_bin}" ] && find_crc32_bin
14   if [ -z "${crc32_bin}" ]
15   then
16     echo "No crc32 algo found!" >&2
17     echo "deadbeef"
18   else
19     echo -n "${*}" | eval "${crc32_bin}" | awk '{print $1}'
20   fi
21 }
22
23 find_crc32_bin() {
24   crc32=""
25   for bin in crc32sum crc32sum-linux crc32sum-freebsd
26   do
27     bin="$(which "${bin}" 2>/dev/null)"
28     if [ -x "${bin}" ]
29     then
30       export crc32_bin="${bin}"
31       if [ "$(hash_string "meow" 2>/dev/null)" = "8a106afe" ]
32       then
33         crc32="${bin}"
34         break
35       fi
36     fi
37   done
38
39   if [ -z "${crc32}" ]
40   then
41     for bin in cksum ruby php perl
42     do
43       bin="$(which "${bin}" 2>/dev/null)"
44       if [ -x "${bin}" ]
45       then
46         case "${bin}" in
47         */cksum) bin="printf '%08x\n' \$(${bin} -o 3) | head -n 1" ;;
48         */ruby)  bin="${bin} -e 'require \"zlib\"; printf(\"%08x\n\", Zlib.crc32(STDIN.readlines.join))'" ;;
49         */php)   bin="${bin} -r 'printf(\"%08x\n\", crc32(file_get_contents(\"/dev/stdin\")));'" ;;
50         */perl)  bin="${bin} -e 'use String::CRC32; printf(\"%08x\n\", crc32(*STDIN));'" ;;
51         esac
52         export crc32_bin="${bin}"
53         if [ "$(hash_string "meow" 2>/dev/null)" = "8a106afe" ]
54         then
55           crc32="${bin}"
56           break
57         fi
58       fi
59     done
60   fi
61   if [ -n "${crc32}" ]
62   then
63     export crc32_bin="${crc32}"
64   else
65     echo "Failed to locate usable crc32 algo" >&2
66     unset crc32_bin
67     return 1
68   fi
69 }
70
71 flagcache(){
72   myhost="$(/bin/hostname -f)"
73   cache="${HOME}/.flag-cache"
74   if [ -f "${cache}" ]
75   then
76     flag_hex="$(awk '/^'${myhost}'/{print $2}' "${cache}")"
77   fi
78   if [ -z "${flag_hex}" ]
79   then
80     flag_hex="$(hash_string "${myhost}")"
81     [ "${crc32_bin}" ] && echo -e "${myhost}\t${flag_hex}" >> "${cache}"
82   fi
83 }
84
85 if [ -f "${HOME}/.flag" ]
86 then
87   flag_hex="$(cat "${HOME}/.flag")"
88 fi
89
90 if [ -z "${flag_hex}" -a -f "/etc/flag" ]
91 then
92   flag_hex="$(cat "/etc/flag")"
93 fi
94
95 if [ -z "${flag_hex}" ]
96 then
97   flagcache
98 fi
99
100 # Now we definitely have flag_hex
101 firstchar() {
102   eval $(echo -n "${data}" | sed -e 's/^\(.\)\(.*\)$/char="\1" data="\2"/g')
103 }
104
105 hexdec() {
106   if [ -z "${1}" ]
107   then
108     echo "0"
109     return
110   fi
111   echo $(( 0x${1} + 0 ))
112 }
113
114 flag() {
115   if [ -z "${1}" ]
116   then
117     echo "Usage: flag 'hexcode' [symbol] [shellmode]" >&2
118     echo "Generates an ANSI color flag using the specified hex codes" >&2
119     echo "Uses the optional symbol (or ' ') to draw the flag" >&2
120     echo "shellmode encapsulates all nonprintable codes in \[\] to" >&2
121     echo " give the shell hints on how long the string is, for proper" >&2
122     echo " wrapping of command prompts." >&2
123     return
124   fi
125   data="${1}"
126   sym="${2}"
127   shm="${3}"
128   [ -n "${shm}" ] && open='\\[' shut='\\]'
129   while [ -n "${data}" ]
130   do
131     firstchar
132     ord=$(hexdec "${char}")
133     bright="0"
134     [ "$(( ${ord} & 8 ))" -gt 0 ] && bright="1;7"
135     colour="$(( ${ord} & 7 ))"
136     printf "${open}\033[%s;3%s;4%sm${shut}%s" "${bright}" "${colour}" "${colour}" "${sym:-${char}}"
137   done
138   printf "${open}\033[0m${shut}"
139 }
140
141 pebkac() {
142    echo "Usage: $(basename "${0}") [-s #] [-e]" >&2
143    echo "Produces a neat little ansi colour 'flag' based off" >&2
144    echo " a hash of the machine's hostname (or settable via" >&2
145    echo " ~/.flag or /etc/flag) which can uniquely visually" >&2
146    echo " identify a machine, at a glance. Useful for placing" >&2
147    echo " into /etc/issue or your bash prompt, so that you" >&2
148    echo " don't send stupid commands to the wrong machine." >&2
149    echo " " >&2
150    echo " -s #   Specify which character should be used to" >&2
151    echo "         render the flag. If empty, use the hex code." >&2
152    echo " -e     Turn on bash encapsulation mode, to provide" >&2
153    echo "         hints to Bash on what is or is not printable" >&2
154    echo "         so it can wrap your commands appropriately" >&2
155    echo "         when used in your prompt" >&2
156    echo " " >&2
157    echo "This machine's flag is as such: ($(flag "${flag_hex}"))" >&2
158    exit 1
159 }
160
161 symbol=""
162 shellmode=""
163
164 while [ -n "${1}" ]
165 do
166   case "${1}" in
167   -s)  shift; symbol="${1}" ;;
168   -e)  shellmode="yes" ;;
169   *)   pebkac ;;
170   esac
171   shift
172 done
173 flag "${flag_hex}" "${symbol}" "${shellmode}"
174