chiark / gitweb /
initial checkin: still somewhat sketchy
[distorted-keys] / keeper-cards
1 #! /bin/sh
2 ###
3 ### Issue cards containing a bunch of keeper secrets
4 ###
5 ### (c) 2011 Mark Wooding
6 ###
7
8 ###----- Licensing notice ---------------------------------------------------
9 ###
10 ### This program is free software; you can redistribute it and/or modify
11 ### it under the terms of the GNU General Public License as published by
12 ### the Free Software Foundation; either version 2 of the License, or
13 ### (at your option) any later version.
14 ###
15 ### This program is distributed in the hope that it will be useful,
16 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ### GNU General Public License for more details.
19 ###
20 ### You should have received a copy of the GNU General Public License
21 ### along with this program; if not, write to the Free Software Foundation,
22 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 set -e
25 case "${KEYSLIB+t}" in t) ;; *) echo >&2 "$0: KEYSLIB unset"; exit 1 ;; esac
26 . "$KEYSLIB"/keyfunc.sh
27
28 defhelp <<HELP
29 KEEPER [INDICES ...]
30 Typeset cards for a set of keeper secrets.
31
32 This program writes a file KEEPER.ps which will contain private keys from the
33 keeper set KEEPER, specifically the keys with the given INDICES.  Elements of
34 the list are either simple integers or ranges [LOW]-[HIGH]; if LOW is
35 omitted, it means 0, and if HIGH is omitted, it means the highest possible
36 index.  If no INDICES are given then all secret keys are written.
37
38 The public keys are found in $KEYS/keeper/KEEPER/I.pub;
39 private keys are read from KEEPER/I in the current directory.
40 HELP
41 dohelp
42
43 ## Parse the command line.
44 case $# in 0) echo >&2 "$usage"; exit 1 ;; esac
45 keeper=$1; shift
46 checkword "keeper set label" "$keeper"
47 read n hunoz <$KEYS/keeper/$keeper/meta
48
49 ## Build a colon-separated list of the indices we actually want.
50 want=:
51 case $# in 0) set 0- ;; esac
52 for range in "$@"; do
53   case "$range" in
54     *[!-0-9]* | *[!0-9]*-* | *-*[!0-9]*)
55       echo >&2 "$quis: bad index range \`$range'"
56       exit 1
57       ;;
58     *-*)
59       low=${range%-*} high=${range#*-}
60       ;;
61     *)
62       low=$range high=$range
63       ;;
64   esac
65   case "$low" in ?*) ;; *) low=0 ;; esac
66   case "$high" in ?*) ;; *) high=$((n - 1)) ;; esac
67   if [ 0 -gt $low -o $low -gt $high -o $high -ge $n ]; then
68     echo >&2 "$quis: invalid index range \`$range'"
69     exit 1
70   fi
71   i=$((low + 0))
72   while [ $i -le $high ]; do
73     case $want in *:"$i":*) ;; *) want=$want$i: ;; esac
74     i=$((i + 1))
75   done
76 done
77
78 ## Start working on the output file.  This will contain deep secrets, so
79 ## don't leave stuff easily readable.
80 tmp=$(mktmp); cleanup rmtmp
81 umask 077
82 exec 3>$tmp/$keeper.tex
83 cat >&3 <<'EOF'
84 \documentclass[a4paper, landscape, 12pt]{article}
85 \usepackage[utf8]{inputenc}
86 \usepackage[T1]{fontenc}
87 \usepackage[palatino, helvetica, courier, maths = cmr]{mdwfonts}
88 \usepackage{graphicx}
89
90 %% Report errors with enough context that we can debug them.
91 \errorcontextlines=999
92
93 %% Basic layout for the cards.  We use the paragraph filling machinery, but
94 %% don't actually need most of the trimmings.
95 \parindent=0pt
96 \parfillskip=0pt
97 \pagestyle{empty}
98
99 %% Page layout: try to use most of the page.  The document class will already
100 %% have set up the paper size, but we do the rest here.
101 \hoffset=-1in \voffset=-1in
102 \oddsidemargin=20mm
103 \textwidth=\paperwidth \advance\textwidth by -2\oddsidemargin
104 \topmargin=20mm
105 \headheight=0pt \headsep=0pt
106 \textheight=\paperheight \advance\textheight by -2\topmargin
107 \AtBeginDocument{\special{papersize=\the\paperwidth,\the\paperheight}}
108
109 %% Parameters for the cards and guide rules.
110 \newdimen\cardwd \cardwd=82mm
111 \newdimen\cardht \cardht=49mm
112 \newdimen\guidelen \guidelen=10mm
113 \newdimen\rulewd \rulewd=0.6pt
114
115 %% Typesetting the secret as text.  The macro \snarf TOKEN T0 T1 ... T7
116 %% gathers T0 T1 ... T7 into a single argument and passes them to TOKEN, as
117 %% long as T0 is not \relax.  We use this to process the secret text in a
118 %% continuation-passing style.
119 \def\snarf#1#2{%
120   \ifx#2\relax\let\next\empty%
121   \else\def\next{\snarfdo#1#2}%
122   \fi%
123   \next%
124 }
125 \def\snarfdo#1#2#3#4#5#6#7#8#9{#1{#2#3#4#5#6#7#8#9}}
126
127 %% Print the left and right halves of the line, with a separator.  Use boxes
128 %% for the lines so that TeX will work out the width of the enclosing vbox
129 %% for us.  The basic usage is \line TEXT \relax ... \relax, with eight
130 %% \relax tokens: this is enough to complete both \snarf calls.
131 \def\line{\snarf\lineleft}
132 \def\lineleft#1{\hbox\bgroup#1 \snarf\lineright}
133 \def\lineright#1{#1\egroup\line}
134
135 %% Typeset a card containing a secret.  Usage is \card{INDEX}{SECRET}.
136 \def\card#1#2{%
137   %%
138   %% Make sure we're setting a paragraph.
139   \leavevmode%
140   %%
141   %% Initial material: a stretchy space on the left.
142   \hbox{}\nobreak\hfil%
143   %%
144   %% An alignment for the guide markers surrounding the actual card.
145   \vbox{\halign{&##\cr%
146     %%
147     %% Top left guides.
148     \vrule width \guidelen height \rulewd depth 0pt%
149     \vrule width \rulewd depth 0pt height \guidelen%
150     &%
151     %%
152     %% Top centre gap.
153     \hfil%
154     &%
155     %%
156     %% Top right guides.
157     \vrule width \rulewd depth 0pt height \guidelen%
158     \vrule width \guidelen height \rulewd depth 0pt%
159     \cr%
160     %%
161     %% Left gap.
162     &%
163     %%
164     %% The actual card.
165     \vbox to \cardht{%
166       %%
167       %% We actually do more or less sensible typesetting.  TeX will set the
168       %% box width from the hsize, and we should leave a small margin all
169       %% around.
170       \parfillskip=0pt plus 1fil%
171       \leftskip=1em \rightskip=1em%
172       \hsize=\cardwd%
173       %%
174       %% The heading.
175       \hrule height 0pt \prevdepth = 0pt%
176       \medskip%
177       {\large\bfseries\textsf{\keeper} secret #1/\total}%
178       %%
179       %% The QR-code and the text of the secret.
180       \vfil%
181       $%
182       \vcenter{\hbox{\includegraphics[scale = 2.4]{#1.eps}}}%
183       \hfil%
184       \vcenter{\ttfamily%
185         \line#2%
186         \relax\relax\relax\relax\relax\relax\relax\relax%
187       }%
188       $%
189       %%
190       %% And we're done.
191       \vfil%
192     }%
193     &%
194     %%
195     %% Right gap.
196     \cr%
197     %%
198     %% Bottom left guides.
199     \vrule width \guidelen depth \rulewd height 0pt%
200     \vrule width \rulewd depth \guidelen height 0pt%
201     &%
202     %% Bottom centre gap.
203     \hfil%
204     &%
205     %% Bottom right guides.
206     \vrule width \rulewd depth \guidelen height 0pt%
207     \vrule width \guidelen depth \rulewd height 0pt%
208     \cr%
209     %%
210     %% Leave a small vertical space at the bottom to separate lines of cards.
211     \strut \cr%
212   }}%
213   %%
214   %% End material: a stretchy space to match the one at the start, and then
215   %% allow a break.
216   \nobreak\hfil\hbox{}%
217   \penalty0%
218 }
219 EOF
220
221 ## Write the basic configuration stuff.
222 cat >&3 <<EOF
223
224 %% General configuration for the cards.
225 \def\keeper{$keeper}
226 \def\total{$n}
227 EOF
228
229 ## Start the document body.
230 cat >&3 <<'EOF'
231
232 %% The actual content.
233 \begin{document}
234 EOF
235
236 ## Work through the requested indices.
237 i=0
238 while [ $i -lt $n ]; do
239   case $want in
240     *:"$i":*)
241       read secret <$keeper/$i
242       tr -d '\n' <$keeper/$i | qrencode -m0 -s1 -o$tmp/$i.png
243       convert $tmp/$i.png $tmp/$i.eps
244       cat >&3 <<EOF
245 \card{$i}{$secret}
246 EOF
247   esac
248   i=$((i + 1))
249 done
250
251 ## Wrap up and build the document.
252 cat >&3 <<'EOF'
253 \end{document}
254 EOF
255 exec 3>&-
256 if ! (cd $tmp
257     exec </dev/null >tex.out 2>&1
258     latex $keeper.tex && dvips -o$keeper.ps $keeper.dvi); then
259   echo >&2 "$quis: document formatting failed"
260   sed >&2 's/^/| /' $tmp/tex.out
261   exit 1
262 fi
263 cp $tmp/$keeper.ps .
264
265 ###----- That's all, folks --------------------------------------------------