git.fiddlerwoaroof.com
Browse code

(init)

Edward Langley authored on 29/09/2019 22:37:07
Showing 12 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,6 @@
1
+*~
2
+.*.sw?
3
+CJAWSAccess.app
4
+app.icns
5
+accounts.json
6
+accounts.yml
0 7
new file mode 100644
... ...
@@ -0,0 +1,15 @@
1
+CJAWSAccess.app: app.icns deliver.lisp src/*.lisp aws-access.asd accounts.json
2
+	/Applications/LispWorks\ 7.1\ \(64-bit\)/LispWorks\ \(64-bit\).app/Contents/MacOS/lispworks-7-1-0-amd64-darwin -build deliver.lisp
3
+	cp accounts.json CJAWSAccess.app/Contents/Resources/accounts.json
4
+	cp app.icns CJAWSAccess.app/Contents/Resources/app.icns
5
+	touch CJAWSAccess.app
6
+
7
+accounts.json: accounts.yml
8
+	./flip-yaml.lisp accounts.yml
9
+
10
+accounts.yml:
11
+	git archive --format=tar --remote=git@gitlab.cj.com:operations-chapter/aws-department.git heads/master -- accounts.yaml | tar xO accounts.yaml > ~/accounts.yml
12
+
13
+app.icns: icon/icon.svg
14
+	$(MAKE) --directory=icon
15
+	cp icon/icon.icns app.icns
0 16
new file mode 100644
... ...
@@ -0,0 +1,23 @@
1
+;;; -*- Mode:Lisp; Syntax:ANSI-Common-Lisp; Package: ASDF-USER -*-
2
+(in-package :asdf-user)
3
+
4
+(defsystem :aws-access 
5
+    :description "A simple tool for access to CJ's AWS accounts"
6
+    :author "Ed L <edward@elangley.org>"
7
+    :license "MIT"
8
+    :depends-on (:alexandria
9
+                 :aws-sdk
10
+                 :aws-sdk/services/sts
11
+                 :cells
12
+                 :cl-yaml
13
+                 :fwoar-lisputils
14
+                 :serapeum
15
+                 :ubiquitous
16
+                 :uiop
17
+                 :yason)
18
+    :serial t
19
+    :components ((:module "src"
20
+                  :serial t
21
+                  :components ((:file "package")
22
+                               (:file "mfa-tool")
23
+                               (:file "capi-interface")))))
0 24
new file mode 100644
... ...
@@ -0,0 +1,23 @@
1
+(in-package :cl-user)
2
+(setf *default-pathname-defaults*
3
+ (make-pathname :directory (pathname-directory *load-pathname*)))
4
+(format t "~&CURDIR: ~a~%" (truename "."))
5
+(load-all-patches)
6
+(load "~/quicklisp/setup.lisp")
7
+(ql:quickload :swank)
8
+(mapcar 'asdf:load-asd
9
+        (directory "*.asd"))
10
+(ql:quickload :aws-access)
11
+
12
+(deliver (intern "MAIN" "MFA-TOOL")
13
+         (create-macos-application-bundle
14
+          "CJAWSAccess.app"
15
+          :document-types nil
16
+          :identifier "fwoar.cj.AWSAccess")
17
+         0
18
+         :KEEP-PRETTY-PRINTER t
19
+         :interface :capi
20
+         :keep-modules t
21
+         :packages-to-keep-symbol-names '(:mfa-tool)
22
+         :packages-to-keep '(:mfa-tool :swank)
23
+         :startup-bitmap-file nil) 
0 24
new file mode 100755
... ...
@@ -0,0 +1,23 @@
1
+#!/usr/bin/env sbcl --script
2
+(eval-when (:compile-toplevel :load-toplevel :execute)
3
+  (load "~/quicklisp/setup.lisp"))
4
+
5
+(eval-when (:compile-toplevel :load-toplevel :execute)
6
+  (ql:quickload '(:cl-yaml :yason :uiop :alexandria)))
7
+
8
+(defparameter *in-file*
9
+  (pathname (first (uiop:command-line-arguments))))
10
+
11
+(defparameter *out-file*
12
+  (make-pathname :type "json"
13
+                 :defaults *in-file*))
14
+
15
+(format t "~a -> ~a" *in-file* *out-file*)
16
+
17
+(defparameter *accounts-in*
18
+  (alexandria:read-file-into-string *in-file*))
19
+
20
+(alexandria:with-output-to-file (out *out-file* :if-exists :supersede)
21
+  (with-open-stream (out-stream (yason:make-json-output-stream out :indent t))
22
+    (yason:encode (cl-yaml:parse *accounts-in*)
23
+                  out-stream)))
0 24
new file mode 100644
... ...
@@ -0,0 +1,2 @@
1
+*.icns
2
+*.iconset
0 3
new file mode 100644
... ...
@@ -0,0 +1,20 @@
1
+all: icon.iconset
2
+	iconutil -c icns icon.iconset 
3
+
4
+icon.iconset: icon.svg
5
+	rm -rf icon.iconset
6
+	mkdir -p icon.iconset
7
+	rsvg-convert -w 16   -h 16   icon.svg > icon.iconset/icon_16x16.png
8
+	rsvg-convert -w 32   -h 32   icon.svg > icon.iconset/icon_16x16@2x.png
9
+	rsvg-convert -w 32   -h 32   icon.svg > icon.iconset/icon_32x32.png
10
+	rsvg-convert -w 64   -h 64   icon.svg > icon.iconset/icon_32x32@2x.png
11
+	rsvg-convert -w 64   -h 64   icon.svg > icon.iconset/icon_64x64.png
12
+	rsvg-convert -w 128	-h 128	icon.svg > icon.iconset/icon_64x64@2x.png
13
+	rsvg-convert -w 128	-h 128	icon.svg > icon.iconset/icon_128x128.png
14
+	rsvg-convert -w 256	-h 256	icon.svg > icon.iconset/icon_128x128@2x.png
15
+	rsvg-convert -w 256	-h 256	icon.svg > icon.iconset/icon_256x256.png
16
+	rsvg-convert -w 512	-h 512	icon.svg > icon.iconset/icon_256x256@2x.png
17
+	rsvg-convert -w 512	-h 512	icon.svg > icon.iconset/icon_512x512.png
18
+	rsvg-convert -w 1024	-h 1024	icon.svg > icon.iconset/icon_512x512@2x.png
19
+	rsvg-convert -w 1024	-h 1024	icon.svg > icon.iconset/icon_1024x1024.png
20
+	rsvg-convert -w 2048	-h 2048	icon.svg > icon.iconset/icon_1024x1024@2x.png
0 21
new file mode 100644
... ...
@@ -0,0 +1,253 @@
1
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+<svg
3
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
4
+   xmlns:cc="http://creativecommons.org/ns#"
5
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
6
+   xmlns:svg="http://www.w3.org/2000/svg"
7
+   xmlns="http://www.w3.org/2000/svg"
8
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
9
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
10
+   xml:space="preserve"
11
+   enable-background="new 0 0 1024 768"
12
+   viewBox="0 0 1024 1024"
13
+   height="1024"
14
+   width="1024"
15
+   y="0px"
16
+   x="0px"
17
+   id="Layer_1"
18
+   version="1.1"
19
+   sodipodi:docname="icon.svg"
20
+   inkscape:version="0.92.2 5c3e80d, 2017-08-06"><sodipodi:namedview
21
+     pagecolor="#ffffff"
22
+     bordercolor="#666666"
23
+     borderopacity="1"
24
+     objecttolerance="10"
25
+     gridtolerance="10"
26
+     guidetolerance="10"
27
+     inkscape:pageopacity="0"
28
+     inkscape:pageshadow="2"
29
+     inkscape:window-width="1918"
30
+     inkscape:window-height="1198"
31
+     id="namedview18"
32
+     showgrid="false"
33
+     inkscape:zoom="0.67285156"
34
+     inkscape:cx="390.87373"
35
+     inkscape:cy="321.77755"
36
+     inkscape:window-x="1"
37
+     inkscape:window-y="1"
38
+     inkscape:window-maximized="0"
39
+     inkscape:current-layer="Layer_1" /><metadata
40
+     id="metadata76"><rdf:RDF><cc:Work
41
+         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
42
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
43
+     id="defs74"><filter
44
+       style="color-interpolation-filters:sRGB;"
45
+       inkscape:label="Drop Shadow"
46
+       id="filter4684"><feFlood
47
+         flood-opacity="0.498039"
48
+         flood-color="rgb(0,0,0)"
49
+         result="flood"
50
+         id="feFlood4674" /><feComposite
51
+         in="flood"
52
+         in2="SourceGraphic"
53
+         operator="in"
54
+         result="composite1"
55
+         id="feComposite4676" /><feGaussianBlur
56
+         in="composite1"
57
+         stdDeviation="3"
58
+         result="blur"
59
+         id="feGaussianBlur4678" /><feOffset
60
+         dx="16"
61
+         dy="16"
62
+         result="offset"
63
+         id="feOffset4680" /><feComposite
64
+         in="SourceGraphic"
65
+         in2="offset"
66
+         operator="over"
67
+         result="fbSourceGraphic"
68
+         id="feComposite4682" /><feColorMatrix
69
+         result="fbSourceGraphicAlpha"
70
+         in="fbSourceGraphic"
71
+         values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
72
+         id="feColorMatrix4686" /><feFlood
73
+         id="feFlood4688"
74
+         flood-opacity="0.498039"
75
+         flood-color="rgb(0,0,0)"
76
+         result="flood"
77
+         in="fbSourceGraphic" /><feComposite
78
+         in2="fbSourceGraphic"
79
+         id="feComposite4690"
80
+         in="flood"
81
+         operator="in"
82
+         result="composite1" /><feGaussianBlur
83
+         id="feGaussianBlur4692"
84
+         in="composite1"
85
+         stdDeviation="3"
86
+         result="blur" /><feOffset
87
+         id="feOffset4694"
88
+         dx="16"
89
+         dy="16"
90
+         result="offset" /><feComposite
91
+         in2="offset"
92
+         id="feComposite4696"
93
+         in="fbSourceGraphic"
94
+         operator="over"
95
+         result="fbSourceGraphic" /><feColorMatrix
96
+         result="fbSourceGraphicAlpha"
97
+         in="fbSourceGraphic"
98
+         values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
99
+         id="feColorMatrix4698" /><feFlood
100
+         id="feFlood4700"
101
+         flood-opacity="0.498039"
102
+         flood-color="rgb(0,0,0)"
103
+         result="flood"
104
+         in="fbSourceGraphic" /><feComposite
105
+         in2="fbSourceGraphic"
106
+         id="feComposite4702"
107
+         in="flood"
108
+         operator="in"
109
+         result="composite1" /><feGaussianBlur
110
+         id="feGaussianBlur4704"
111
+         in="composite1"
112
+         stdDeviation="3"
113
+         result="blur" /><feOffset
114
+         id="feOffset4706"
115
+         dx="16"
116
+         dy="16"
117
+         result="offset" /><feComposite
118
+         in2="offset"
119
+         id="feComposite4708"
120
+         in="fbSourceGraphic"
121
+         operator="over"
122
+         result="composite2" /></filter><inkscape:perspective
123
+       id="perspective4636"
124
+       inkscape:persp3d-origin="75.5 : 32.666667 : 1"
125
+       inkscape:vp_z="151 : 49 : 1"
126
+       inkscape:vp_y="0 : 1000 : 0"
127
+       inkscape:vp_x="0 : 49 : 1"
128
+       sodipodi:type="inkscape:persp3d" /><inkscape:perspective
129
+       id="perspective4636-4"
130
+       inkscape:persp3d-origin="75.5 : 32.666667 : 1"
131
+       inkscape:vp_z="151 : 49 : 1"
132
+       inkscape:vp_y="0 : 1000 : 0"
133
+       inkscape:vp_x="0 : 49 : 1"
134
+       sodipodi:type="inkscape:persp3d" /><filter
135
+       y="-0.25"
136
+       height="1.5"
137
+       inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
138
+       inkscape:menu="Shadows and Glows"
139
+       inkscape:label="Dark and Glow"
140
+       style="color-interpolation-filters:sRGB;"
141
+       id="filter7493"><feGaussianBlur
142
+         stdDeviation="5"
143
+         result="result6"
144
+         id="feGaussianBlur7483" /><feComposite
145
+         result="result8"
146
+         in="SourceGraphic"
147
+         operator="atop"
148
+         in2="result6"
149
+         id="feComposite7485" /><feComposite
150
+         result="result9"
151
+         operator="over"
152
+         in2="SourceAlpha"
153
+         in="result8"
154
+         id="feComposite7487" /><feColorMatrix
155
+         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
156
+         result="result10"
157
+         id="feColorMatrix7489" /><feBlend
158
+         in="result10"
159
+         mode="normal"
160
+         in2="result6"
161
+         id="feBlend7491" /></filter></defs><g
162
+     inkscape:label="Calque 1"
163
+     id="g7446"
164
+     transform="matrix(5.5905096,0,0,6.8498347,89.916518,-6360.8651)"
165
+     style="filter:url(#filter7493)"><g
166
+       style="opacity:0.67801855"
167
+       id="g7444"><path
168
+         inkscape:connector-curvature="0"
169
+         id="path7406"
170
+         d="m 104.7944,978.86598 c 0,13.52888 -13.79395,24.49622 -30.80965,24.49622 -17.01571,0 -30.80966,-10.96734 -30.80966,-24.49622 0,-13.52887 13.79395,-24.4962 30.80966,-24.4962 17.0157,0 30.80965,10.96733 30.80965,24.4962 z"
171
+         style="fill:#091119;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
172
+         inkscape:connector-curvature="0"
173
+         id="path7408"
174
+         d="m 103.42412,979.70978 c 0,13.43025 -13.23431,24.31762 -29.55965,24.31762 -16.32535,0 -29.55966,-10.88737 -29.55966,-24.31762 0,-13.43026 13.23431,-24.31763 29.55966,-24.31763 16.32534,0 29.55965,10.88737 29.55965,24.31763 z"
175
+         style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
176
+         inkscape:connector-curvature="0"
177
+         id="path7410"
178
+         d="m 106.05711,1009.9282 c 0,12.2736 -11.19345,22.2233 -25.00127,22.2233 -13.80783,0 -25.00128,-9.9497 -25.00128,-22.2233 0,-12.27363 11.19345,-22.22337 25.00128,-22.22337 13.80782,0 25.00127,9.94974 25.00127,22.22337 z"
179
+         style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
180
+         inkscape:connector-curvature="0"
181
+         id="path7412"
182
+         d="m 125.75508,992.7556 c 0,12.2736 -11.19345,22.2234 -25.00127,22.2234 -13.80783,0 -25.00128,-9.9498 -25.00128,-22.2234 0,-12.27362 11.19345,-22.22336 25.00128,-22.22336 13.80782,0 25.00127,9.94974 25.00127,22.22336 z"
183
+         style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
184
+         inkscape:connector-curvature="0"
185
+         id="path7414"
186
+         d="m 70.19668,999.82666 c 0,12.27364 -11.19345,22.22334 -25.00127,22.22334 -13.80783,0 -25.00128,-9.9497 -25.00128,-22.22334 0,-12.27362 11.19345,-22.22336 25.00128,-22.22336 13.80782,0 25.00127,9.94974 25.00127,22.22336 z"
187
+         style="fill:#050a0f;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
188
+         inkscape:connector-curvature="0"
189
+         id="path7416"
190
+         d="m 72.61576,1000.9598 c 0,12.2736 -11.47328,22.2233 -25.62628,22.2233 -14.153,0 -25.62627,-9.9497 -25.62627,-22.2233 0,-12.27364 11.47327,-22.22338 25.62627,-22.22338 14.153,0 25.62628,9.94974 25.62628,22.22338 z"
191
+         style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
192
+         inkscape:connector-curvature="0"
193
+         id="path7418"
194
+         d="m 40.3972,1019.2721 c 0,9.9026 -8.93215,17.9302 -19.95051,17.9302 -11.01837,0 -19.95051,-8.0276 -19.95051,-17.9302 0,-9.9026 8.93214,-17.9302 19.95051,-17.9302 11.01836,0 19.95051,8.0276 19.95051,17.9302 z"
195
+         style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
196
+         inkscape:connector-curvature="0"
197
+         id="path7420"
198
+         d="m 40.95786,1019.699 c 0,9.3048 -8.77225,16.8479 -19.59337,16.8479 -10.82112,0 -19.59338,-7.5431 -19.59338,-16.8479 0,-9.3049 8.77226,-16.848 19.59338,-16.848 10.82112,0 19.59337,7.5431 19.59337,16.848 z"
199
+         style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
200
+         inkscape:connector-curvature="0"
201
+         id="path7422"
202
+         d="m 126.18719,994.88834 c 0,12.86536 -11.39333,23.29476 -25.44771,23.29476 -14.05438,0 -25.44771,-10.4294 -25.44771,-23.29476 0,-12.86535 11.39333,-23.29478 25.44771,-23.29478 14.05438,0 25.44771,10.42943 25.44771,23.29478 z"
203
+         style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
204
+         inkscape:connector-curvature="0"
205
+         id="path7424"
206
+         d="m 150.50382,1000.3317 c 0,12.2737 -11.19345,22.2234 -25.00127,22.2234 -13.80783,0 -25.00128,-9.9497 -25.00128,-22.2234 0,-12.27358 11.19345,-22.22332 25.00128,-22.22332 13.80782,0 25.00127,9.94974 25.00127,22.22332 z"
207
+         style="fill:#030508;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
208
+         inkscape:connector-curvature="0"
209
+         id="path7426"
210
+         d="m 149.75861,1000.2455 c 0,11.5833 -11.2734,20.9733 -25.17984,20.9733 -13.90645,0 -25.17985,-9.39 -25.17985,-20.9733 0,-11.58327 11.2734,-20.97337 25.17985,-20.97337 13.90644,0 25.17984,9.3901 25.17984,20.97337 z"
211
+         style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
212
+         inkscape:connector-curvature="0"
213
+         id="path7428"
214
+         d="m 41.91242,1033.6668 c 0,6.5552 -5.201,11.8693 -11.61676,11.8693 -6.41575,0 -11.61675,-5.3141 -11.61675,-11.8693 0,-6.5553 5.201,-11.8693 11.61675,-11.8693 6.41576,0 11.61676,5.314 11.61676,11.8693 z"
215
+         style="fill:#030609;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
216
+         inkscape:connector-curvature="0"
217
+         id="path7430"
218
+         d="m 42.26694,1032.9241 c 0,6.4566 -5.12105,11.6907 -11.43818,11.6907 -6.31714,0 -11.43819,-5.2341 -11.43819,-11.6907 0,-6.4566 5.12105,-11.6908 11.43819,-11.6908 6.31713,0 11.43818,5.2342 11.43818,11.6908 z"
219
+         style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
220
+         inkscape:connector-curvature="0"
221
+         id="path7432"
222
+         d="m 84.33882,1030.1312 c 0,12.2737 -11.19345,22.2234 -25.00127,22.2234 -13.80783,0 -25.00128,-9.9497 -25.00128,-22.2234 0,-12.2736 11.19345,-22.2233 25.00128,-22.2233 13.80782,0 25.00127,9.9497 25.00127,22.2233 z"
223
+         style="fill:#050505;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
224
+         inkscape:connector-curvature="0"
225
+         id="path7434"
226
+         d="m 84.47542,1029.5542 c 0,12.0144 -10.93019,21.7539 -24.41325,21.7539 -13.48308,0 -24.41327,-9.7395 -24.41327,-21.7539 0,-12.0144 10.93019,-21.754 24.41327,-21.754 13.48306,0 24.41325,9.7396 24.41325,21.754 z"
227
+         style="fill:#eeeeec;fill-opacity:0.99466672;fill-rule:nonzero;stroke:none" /><path
228
+         inkscape:connector-curvature="0"
229
+         id="path7436"
230
+         d="m 139.39213,1020.0297 c 0,12.2736 -11.19345,22.2234 -25.00127,22.2234 -13.80783,0 -25.00128,-9.9498 -25.00128,-22.2234 0,-12.2736 11.19345,-22.22335 25.00128,-22.22335 13.80782,0 25.00127,9.94975 25.00127,22.22335 z"
231
+         style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
232
+         inkscape:connector-curvature="0"
233
+         id="path7438"
234
+         d="m 138.06218,1019.7544 c 0,11.8052 -11.21344,21.3752 -25.04592,21.3752 -13.83248,0 -25.04591,-9.57 -25.04591,-21.3752 0,-11.8051 11.21343,-21.37511 25.04591,-21.37511 13.83248,0 25.04592,9.57001 25.04592,21.37511 z"
235
+         style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
236
+         inkscape:connector-curvature="0"
237
+         id="path7440"
238
+         d="m 90.95831,1047.975 c -7.9716,1.3183 -15.50224,-3.8048 -16.82016,-11.4427 -1.31791,-7.638 4.07596,-14.8984 12.04756,-16.2166 7.9716,-1.3183 15.50224,3.8048 16.82016,11.4428 1.31792,7.6379 -4.07596,14.8983 -12.04756,16.2165 z"
239
+         style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
240
+         inkscape:connector-curvature="0"
241
+         id="path7442"
242
+         d="m 91.26841,1046.5778 c -7.83783,1.3182 -15.2421,-3.8049 -16.5379,-11.4428 -1.2958,-7.6379 4.00756,-14.8984 11.84539,-16.2166 7.83783,-1.3183 15.24211,3.8048 16.53791,11.4428 1.29579,7.6379 -4.00757,14.8983 -11.8454,16.2166 z"
243
+         style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g><g
244
+     transform="matrix(0.71451596,0,0,0.71451596,145.64446,237.62552)"
245
+     id="g69"><path
246
+       inkscape:connector-curvature="0"
247
+       style="fill:#ffffff;stroke:#000000;stroke-width:13.11448288;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
248
+       id="path65"
249
+       d="m 465.388,355.317 c 28.549,0 142.254,0 142.254,0 0,0 -29.512,147.712 -29.562,148.266 -1.721,7.28 -7.158,18.114 -17.398,26.398 l -0.982,0.85 c -8.028,6.277 -19.036,11.183 -33.669,11.183 0,0 -80.374,0 -100.199,0 -3.174,14.971 -10.485,50.391 -14.807,71.465 26.174,0 93.87,0 93.87,0 132.024,0 158.075,-112.477 159.068,-117.022 0,0 37.714,-181.955 44.134,-213.259 -30.935,0 -206.868,0.369 -227.922,0.369 -3.022,14.97 -10.354,50.625 -14.787,71.75 z" /><path
250
+       inkscape:connector-curvature="0"
251
+       style="fill:#ffffff;stroke:#000000;stroke-width:13.11448288;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
252
+       id="path67"
253
+       d="m 522.179,483.993 c 3.185,-14.909 10.383,-50.38 14.889,-71.628 -26.357,0 -94.505,0 -94.505,0 -2.038,0 -16.742,-1.004 -28.201,-10.312 -1.781,-1.505 -3.543,-3.153 -5.059,-5.119 -0.204,-0.175 -0.297,-0.257 -0.43,-0.554 -8.95,-11.396 -6.462,-26.204 -5.857,-29.419 0,0 21.136,-102.247 21.197,-102.697 1.73,-7.281 7.127,-17.777 17.131,-26.102 l 1.71,-1.403 c 8.162,-6.185 18.914,-10.721 33.332,-10.721 0,0 80.312,0 100.219,0 3.071,-15.216 10.424,-50.483 14.756,-71.516 -26.215,0 -93.87,0 -93.87,0 -132.086,0 -158.024,112.169 -159.161,116.838 l -21.002,101.98 c -0.102,0.543 -8.786,47.524 17.808,79.289 17.408,20.858 46.551,31.354 86.846,31.354 0.019,0.01 80.311,0.01 100.197,0.01 z" /></g></svg>
0 254
\ No newline at end of file
1 255
new file mode 100644
... ...
@@ -0,0 +1,145 @@
1
+(in-package :mfa-tool)
2
+
3
+(capi:define-interface mfa-tool ()
4
+  ((%default-account :initarg :default-account :reader default-account)
5
+   (%signin-url :accessor signin-url))
6
+  (:panes
7
+   (output-pane capi:collector-pane :reader output
8
+                                    :visible-min-width (list :character 80)
9
+                                    :visible-min-height (list :character 25))
10
+   (go-button capi:push-button :text "Go!" :callback 'go-on)
11
+   (mfa-input capi:text-input-pane
12
+              :title "MFA Token:"
13
+              :title-position :left
14
+              :max-characters 6
15
+              :callback 'go-on
16
+              :title-args '(:visible-min-width (:character 11))
17
+              :reader mfa-input)
18
+   (user-input capi:text-input-pane
19
+               :title "Email:"
20
+               :title-position :left
21
+               :text (format nil "~a@cj.com" (uiop/os:getenv "USER"))
22
+               :title-args '(:visible-min-width (:character 11))
23
+               :reader user-input)
24
+   (account-selector capi:option-pane
25
+                     :print-function 'car
26
+                     :items *accounts*
27
+                     :selected-item (rassoc %default-account *accounts*
28
+                                            :test 'equal)
29
+                     :selection-callback 'account-selected
30
+                     :callback-type :data
31
+                     :reader account-selector)
32
+   (action-buttons capi:push-button-panel
33
+                   :items '(:|Open Web Console|
34
+                            :|Authorize iTerm|)
35
+                   :selection-callback 'execute-action
36
+                   :callback-type :data-interface)
37
+   (listener-button capi:push-button
38
+                    :data :|Lisp REPL|
39
+                          :callback 'execute-action
40
+                          :callback-type :data-interface))
41
+  (:layouts
42
+   (button-layout capi:row-layout
43
+                  '(nil
44
+                    go-button))
45
+   (data-layout  capi:column-layout
46
+                 '(account-selector
47
+                   :separator
48
+                   user-input
49
+                   mfa-input
50
+                   button-layout))
51
+   (action-layout capi:row-layout
52
+                  `(listener-button
53
+                    nil
54
+                    action-buttons))
55
+   (right-layout capi:column-layout
56
+                 '(output-pane
57
+                   action-layout))
58
+   (main-layout capi:row-layout
59
+                '(data-layout 
60
+                  right-layout)))
61
+
62
+
63
+  (:default-initargs
64
+   :layout 'main-layout
65
+   :title "CJ AWS Util"))
66
+
67
+(defgeneric execute-action (action interface)
68
+  (:method ((action (eql :|Open Web Console|)) (interface mfa-tool))
69
+    (open-url (signin-url interface)))
70
+  (:method ((action (eql :|Authorize iTerm|)) (interface mfa-tool))
71
+    (uiop:run-program (format nil "osascript '~a'" 
72
+                              (probe-file 
73
+                               (merge-pathnames (make-pathname :name "AuthorizeShell" :type "scpt") 
74
+                                                (bundle-resource-root))))))
75
+  (:method ((action (eql :|Lisp REPL|)) (interface mfa-tool))
76
+    (capi:contain (make-instance 'capi:listener-pane)
77
+                  :best-width 1280
78
+                  :best-height 800)))
79
+
80
+(defun interface (&rest args &key default-account)
81
+  (declare (ignore default-account))
82
+  (let ((interface (apply 'make-instance 'mfa-tool args)))
83
+    (setf (capi:pane-initial-focus interface)
84
+          (slot-value interface 'mfa-input))
85
+    (capi:set-button-panel-enabled-items (slot-value interface 'action-buttons)
86
+                                         :set nil)
87
+    (capi:set-application-interface (make-instance 'my-app-interface))
88
+    (capi:display interface)))
89
+
90
+(eval-when (:compile-toplevel :load-toplevel :execute)
91
+  (defun debugging (condition fun)
92
+    (declare (ignore fun))
93
+    (let ((*print-readably* nil)
94
+          (out (make-instance 'capi:collector-pane)))
95
+      (princ condition (capi:collector-pane-stream out))
96
+      (prin1 (mapcar 'restart-name
97
+                     (compute-restarts condition) )
98
+             (capi:collector-pane-stream out))
99
+      (capi:contain out)
100
+      (abort))))
101
+
102
+(capi:define-interface my-app-interface (capi:cocoa-default-application-interface)
103
+  ()
104
+  (:menus 
105
+   (edit-menu
106
+    "Edit"
107
+    (undo-component standard-edit-component selection-component)
108
+    :callback-type :interface)
109
+   (window-menu
110
+    "Window"
111
+    (("Close Window" 
112
+      :accelerator "accelerator-w"
113
+      :enabled-function 'close-active-screen-enabled
114
+      :callback 'close-active-screen
115
+      :callback-type nil)))
116
+   (standard-edit-component
117
+    :component
118
+    (("Cut" :callback 'capi:active-pane-cut
119
+            :enabled-function 'capi:active-pane-cut-p)
120
+     ("Copy" :callback 'capi:active-pane-copy
121
+             :enabled-function 'capi:active-pane-copy-p)
122
+     ("Paste" :callback 'capi:active-pane-paste
123
+              :enabled-function 'capi:active-pane-paste-p)))
124
+
125
+   (selection-component
126
+    :component
127
+    (("Select All" :callback 'capi:active-pane-select-all)))
128
+   
129
+   (undo-component
130
+    :component
131
+    (("Undo" :data :undo
132
+             :enabled-function 'capi:active-pane-undo-p
133
+             :callback 'capi:active-pane-undo))))
134
+
135
+  (:menu-bar edit-menu window-menu))
136
+
137
+(defun main ()
138
+  (setf *debugger-hook* 'debugging
139
+        *print-readably* nil
140
+        *accounts* (reprocess-accounts (load-accounts)))
141
+  (ubiquitous:restore :cj.mfa-tool)
142
+  (let ((*debugger-hook* 'debugging))
143
+    (setf aws:*session* (aws:make-session))
144
+    (interface :default-account 
145
+               (ubiquitous:value :default-account))))
0 146
new file mode 100644
... ...
@@ -0,0 +1,73 @@
1
+(in-package :mfa-tool)
2
+
3
+(defvar *accounts* ())
4
+
5
+(defun session-name ()
6
+  (format nil "bootstrap~d" (+ 5000 (random 5000))))
7
+
8
+(defparameter *user_management_account_id* 597974043991)
9
+
10
+
11
+(defun do-auth (user role token account)
12
+  (let ((mfa-serial-number
13
+          (format nil "arn:aws:iam::~a:mfa/~a"
14
+                  *user_management_account_id*
15
+                  user))
16
+        (role-arn
17
+          (format nil "arn:aws:iam::~a:role/cjorganization/~a"
18
+                  account
19
+                  role)))
20
+    (aws/sts:assume-role :role-arn role-arn
21
+                         :role-session-name (session-name)
22
+                         :serial-number mfa-serial-number
23
+                         :duration-seconds #.(* 12 60 60)
24
+                         :token-code token)))
25
+
26
+(defun get-url (params)
27
+  (format nil "https://signin.aws.amazon.com/federation?Action=getSigninToken&Session=~a"
28
+          (quri.encode:url-encode (with-output-to-string (s)
29
+                                    (yason:encode params s))
30
+                                  :space-to-plus t)))
31
+
32
+(cells:defmodel 
33
+    sts-result-handler ()
34
+  ((api-result :initarg :api-result :accessor api-result :initform (cells:c-in nil))
35
+   (credentials :reader credentials
36
+                :initform (cells:c? (serapeum:assocdr "Credentials" (^api-result)
37
+                                                      :test 'equal)))
38
+   (session-id :reader session-id
39
+               :initform (cells:c? (serapeum:assocadr "AccessKeyId" (^credentials)
40
+                                                      :test 'equal)))
41
+   (session-key :reader session-key 
42
+                :initform (cells:c? (serapeum:assocadr "SecretAccessKey" (^credentials)
43
+                                                       :test 'equal)))
44
+   (session-token :reader session-token 
45
+                  :initform (cells:c? (serapeum:assocadr "SessionToken" (^credentials)
46
+                                                         :test 'equal)))
47
+   (url-params :reader url-params 
48
+               :initform (cells:c? (fw.lu:alist-string-hash-table
49
+                                    `(("sessionId" . ,(^session-id))
50
+                                      ("sessionKey" . ,(^session-key))
51
+                                      ("sessionToken" . ,(^session-token)))) ))
52
+   (url :reader url
53
+        :initform (cells:c? (get-url (^url-params))))))
54
+
55
+(defun url-from-signin-token (signin-token)
56
+  (format nil "https://signin.aws.amazon.com/federation?Action=login&Destination=https%3A%2F%2Fconsole.aws.amazon.com&SigninToken=~a"
57
+          signin-token))
58
+
59
+(defun run-process (account user token)
60
+  (let* ((api-result (cells:c-in (do-auth user "CJDeveloperAccessRole" token account)))
61
+         (parser (make-instance 'sts-result-handler :api-result api-result))
62
+         (federation-url (url parser))
63
+         (signin-token (gethash "SigninToken" 
64
+                                (yason:parse
65
+                                 (dexador:get federation-url)))))
66
+    (values signin-token
67
+            parser)))
68
+
69
+(defun open-url (url)
70
+  (capi:contain (make-instance 'capi:browser-pane
71
+                               :url url)
72
+                :best-width 1280
73
+                :best-height 800))
0 74
new file mode 100644
... ...
@@ -0,0 +1,82 @@
1
+(in-package :mfa-tool)
2
+
3
+(defun account-selected (account)
4
+  (format t "~s" account)
5
+  (setf (ubiquitous:value :default-account)
6
+        (cdr account)))
7
+
8
+(defparameter *developer-p* (equal "elangley" (uiop/os:getenv "USER")))
9
+
10
+(defun bundle-resource-root ()
11
+  (make-pathname :directory
12
+                 (pathname-directory
13
+                  (objc:invoke-into 'string
14
+                                    (objc:invoke "NSBundle" "mainBundle") 
15
+                                    "pathForResource:ofType:" "app" "icns"))))
16
+
17
+(defun clear-cookies ()
18
+  (let ((cookie-storage (objc:invoke "NSHTTPCookieStorage" "sharedHTTPCookieStorage")))
19
+    (map nil
20
+         (lambda (cookie) 
21
+           (objc:invoke cookie-storage "deleteCookie:" cookie))
22
+         (objc:invoke-into 'array cookie-storage "cookies"))))
23
+
24
+(defun go-on (_ interface)
25
+  (declare (ignore _))
26
+  (let ((token (capi:text-input-pane-text (mfa-input interface)))
27
+        (user-name (capi:text-input-pane-text (user-input interface)))
28
+        (account (cdr (capi:choice-selected-item (account-selector interface)))))
29
+    (clear-cookies)
30
+    (multiple-value-bind (signin-token creds) (run-process account user-name token)
31
+      (with-open-file (stream (make-pathname :name ""
32
+                                             :type "cj-aws"
33
+                                             :defaults (user-homedir-pathname))
34
+                              :direction :output
35
+                              :if-exists :rename
36
+                              :if-does-not-exist :create)
37
+        (format (make-broadcast-stream stream
38
+                                       (capi:collector-pane-stream (output interface)))
39
+                "export AWS_ACCESS_KEY_ID='~a'~%export AWS_SECRET_ACCESS_KEY='~a'~%export AWS_SESSION_TOKEN='~a'~%"
40
+                (session-id creds)
41
+                (session-key creds)
42
+                (session-token creds)))
43
+      (capi:set-button-panel-enabled-items (slot-value interface 'action-buttons)
44
+                                           :set t)
45
+      (setf (signin-url interface) 
46
+            (url-from-signin-token signin-token)))))
47
+
48
+(defun close-active-screen ()
49
+  (let ((active-interface
50
+          (capi:screen-active-interface
51
+           (capi:convert-to-screen))))
52
+    (unless (typep active-interface 'mfa-tool)
53
+      (capi:destroy active-interface))))
54
+
55
+
56
+(defun close-active-screen-enabled ()
57
+  (let ((active-interface
58
+          (capi:screen-active-interface
59
+           (capi:convert-to-screen))))
60
+    (typep active-interface '(not mfa-tool))))
61
+
62
+(defun load-accounts ()
63
+  (yason:parse
64
+   (alexandria:read-file-into-string
65
+    (merge-pathnames (make-pathname :name "accounts"
66
+                                    :type "json")
67
+                     (bundle-resource-root)))))
68
+
69
+(defun reprocess-accounts (accounts)
70
+  (let ((accounts (gethash "Accounts" accounts))
71
+        (result ()))
72
+    (mapc (lambda (account)
73
+            (push (cons (format nil "~a (~a)" 
74
+                                (gethash "Name" account)
75
+                                (gethash "Type" account))
76
+                        (gethash "Id" account))
77
+                  result))
78
+          accounts)
79
+    (coerce (sort result 'string-lessp 
80
+                  :key 'car)
81
+            'list)))
82
+
0 83
new file mode 100644
... ...
@@ -0,0 +1,3 @@
1
+(defpackage :mfa-tool
2
+  (:use :cl)
3
+  (:export :main))