-
Notifications
You must be signed in to change notification settings - Fork 7
/
index.html
305 lines (269 loc) · 11.8 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>AWS S3 Expiring Link Generator</title>
<meta name="description" content="AWS S3 Expiring Link Generator">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="apple-touch-icon-precomposed" href="/favicon/simple-fruit-watermelon-152-8533.png">
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="/favicon/simple-fruit-watermelon-152-8533.png">
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="/favicon/simple-fruit-watermelon-144-8533.png">
<link rel="apple-touch-icon-precomposed" sizes="120x120" href="/favicon/simple-fruit-watermelon-120-8533.png">
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="/favicon/simple-fruit-watermelon-114-8533.png">
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="/favicon/simple-fruit-watermelon-72-8533.png">
<link rel="apple-touch-icon-precomposed" href="/favicon/simple-fruit-watermelon-57-8533.png">
<link rel="icon" href="/favicon/simple-fruit-watermelon-32-8533.png" sizes="32x32">
<meta name="msapplication-TileColor" content="#ffffff" />
<script src="//cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/hmac-sha256.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(function() {
// Shamelessly Stolen from https://stackoverflow.com/questions/617647/where-is-my-one-line-implementation-of-rot13-in-javascript-going-wrong
var rot13 = function(s) {
return s.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);});
}
// We purposefully obfuscate the access key and secret here.
// AWS will disable an account if it finds a compromised key in the wild.
var accessKey = 'NXVNV3QFZCKNO5EV63AN';
var secretKey = 'WGEPmju4SKNorfKDxDxkSkjQHqUL0aS1N+sxtICt';
$('#access_key').val(rot13(accessKey));
$('#secret_key').val(rot13(secretKey));
var parsedURL = function(url) {
var encodedURL = encodeURI(url);
var url_split = encodedURL.split(/\/+/);
return {
"original": url,
"protocol": url_split[0] + "//",
"domain": url_split[1],
"path": "/" + (url_split.length >= 3 ? url_split.slice(2) : []).join("/")
}
};
var urlSigningParams = function(access, expiration, region, iso8601, shortDate) {
var params = '';
params += "X-Amz-Algorithm=AWS4-HMAC-SHA256&";
params += "X-Amz-Credential=" + access + "%2F" + shortDate + "%2F" + region + "%2Fs3%2Faws4_request&";
params += "X-Amz-Date=" + iso8601 + "&";
params += "X-Amz-Expires=" + expiration + "&";
params += "X-Amz-SignedHeaders=host"
return params;
};
var canonicalRequest = function(parsed, params) {
var request = "GET\n";
request += parsed.path + "\n";
request += params + "\n";
request += "host:" + parsed.domain + "\n\n";
request += "host\n";
request += "UNSIGNED-PAYLOAD";
return request;
};
var stringToSign = function(iso8601, shortDate, canonicalReq, region) {
var str = "AWS4-HMAC-SHA256\n";
str += iso8601 + "\n";
str += shortDate + "/" + region + "/s3/aws4_request\n";
str += CryptoJS.SHA256(canonicalReq).toString();
return str;
};
var hmacSHA256 = function(a, b) {
// AWS Docs pass the secret first, we swap it to be compatible
return CryptoJS.HmacSHA256(b, a);
};
var signingKey = function(secret, shortDate, region) {
return hmacSHA256(hmacSHA256(hmacSHA256(hmacSHA256("AWS4" + secret, shortDate), region), "s3"), "aws4_request");
};
var signedURL = function(url, requestParamStr, signature) {
var signedURLStr = url + "?";
signedURLStr += requestParamStr;
signedURLStr += '&X-Amz-Signature=' + signature;
return signedURLStr;
};
$('#expiry-submit').on('click', function(e){
e.preventDefault();
var form = $(e.target).closest('form');
formBlob = {};
form.serializeArray().forEach(function(obj) {
formBlob[obj.name] = obj.value;
});
var url = formBlob.url;
var access = formBlob.access_key;
var secret = formBlob.secret_key;
var expiration = formBlob.expiration;
var region = formBlob.region
var date = new Date();
var iso8601 = date.toISOString().replace(/\-|:|\.\d+/g, '');
var shortDate = iso8601.replace(/T.*/, '');
var parsedURLArr = parsedURL(url);
// console.log("Parsed: ", parsedURLArr);
var requestParamStr = urlSigningParams(access, expiration, region, iso8601, shortDate);
var canonicalReq = canonicalRequest(parsedURLArr, requestParamStr);
// console.log("Canonical: ", canonicalReq);
var stringToSignVar = stringToSign(iso8601, shortDate, canonicalReq, region);
// console.log("SigningStr: ", stringToSignVar);
var signingKeyVar = signingKey(secret, shortDate, region);
// console.log("SigningKey: ", signingKeyVar.toString());
var signature = hmacSHA256(signingKeyVar, stringToSignVar).toString();
// console.log("Signature: ", signature);
var signedURLStr = signedURL(url, requestParamStr, signature);
// console.log("URL: ", signedURLStr);
$('#generated-urls-header').fadeIn();
$('#generated-urls').fadeIn().prepend($('<li>').append($('<a>').attr('href', signedURLStr).text(url)).hide().fadeIn());
});
});
</script>
<link rel="stylesheet" href="/pure-min-0.5.0.css">
<style>
.content {
margin: 0 auto;
padding: 0 2em;
max-width: 800px;
margin-bottom: 50px;
line-height: 1.6em;
}
.header {
margin: 0;
color: #333;
text-align: center;
padding: 2.5em 2em 0;
border-bottom: 1px solid #eee;
}
.header h1 {
margin: 0.2em 0;
font-size: 3em;
font-weight: 300;
}
.header h2 {
font-weight: 300;
color: #ccc;
padding: 0;
margin-top: 0;
}
.content-subhead {
margin: 50px 0 20px 0;
font-weight: 300;
color: #888;
}
body {
color: #777;
}
a {
color: #428bca;
text-decoration: none;
background: 0 0;
}
a:active, a:hover {
color: #2a6496;
text-decoration: underline;
outline: 0;
}
a:visited {
color: #428bca;
text-decoration: none;
background: 0 0;
}
.pure-form-aligned .pure-control-group label {
width: 6em;
}
.pure-form input {
width: 28em;
}
.content {
max-width: 90%;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div class="header">
<h1>AWS S3 Expiring Link Generator</h1>
<h2>A quick alternative to the command line</h2>
</div>
<div class="content pure-g">
<div class="pure-u-1-2">
<h2 id="generated-urls-header" class="content-subhead hidden">Generated Links</h2>
<ul id="generated-urls" class="hidden"></ul>
<h2 class="content-subhead">What's all this?</h2>
<p>
Amazon S3 provides a great place to store all sorts of files but sometimes managing permissions can be a bit of a pain.
Built-in to S3 is the ability to generate links to private files that expire after a set period of time.
This tool generates those for you so you don't have to fiddle with the command line or install any 3rd party tools.
</p>
<h2 class="content-subhead">Won't you steal my key?</h2>
<p>
Your secret key is safe, all code runs client side. The <a href="https://github.com/pcorliss/s3-expiry">code is also available</a> in case you don't trust me.
</p>
<h2 class="content-subhead">Who are you?</h2>
<p>
I'm <a href="https://twitter.com/pcorliss">Phil</a>. I sometimes write things at <a href="https://blog.50projects.com">blog.50projects.com</a>
</p>
</div>
<div class="pure-u-1-2">
<h2 class="content-subhead">Enter your S3 URL and Connectivity Info</h2>
<form id="expiry" class="pure-form pure-form-aligned" action="">
<fieldset>
<div class="pure-control-group">
<label for="url">URL</label>
<input type='text' name='url' placeholder="https://[BUCKET].s3.amazonaws.com/[FILE_PATH]" value='https://expiry-test.s3.amazonaws.com/hello.txt'>
</div>
<div class="pure-control-group">
<label for="access_key">AccessKey</label>
<input type='text' id='access_key' name='access_key' placeholder="Your Access Key" value=''>
</div>
<div class="pure-control-group">
<label for="secret_key">SecretKey</label>
<input type='text' id='secret_key' name='secret_key' placeholder="Your Secret Key" value=''>
</div>
<div class="pure-control-group">
<label for="expiration">Expiration</label>
<input type='text' name='expiration' placeholder="Expiration in Seconds (Max 7 Days)" value='86400'>
</div>
<div class="pure-control-group">
<label for="region">Region</label>
<select name='region'>
<option>us-east-1</option>
<option>us-east-2</option>
<option>us-west-1</option>
<option>us-west-2</option>
<option>af-south-1</option>
<option>ap-east-1</option>
<option>ap-south-1</option>
<option>ap-northeast-3</option>
<option>ap-northeast-2</option>
<option>ap-southeast-1</option>
<option>ap-southeast-2</option>
<option>ap-northeast-1</option>
<option>ca-central-1</option>
<option>cn-north-1</option>
<option>cn-northwest-1</option>
<option>eu-central-1</option>
<option>eu-west-1</option>
<option>eu-west-2</option>
<option>eu-south-1</option>
<option>eu-west-3</option>
<option>eu-north-1</option>
<option>me-south-1</option>
<option>sa-east-1</option>
</select><br>
</div>
<div class="pure-controls">
<button id="expiry-submit" type="submit" class="pure-button pure-button-primary">Submit</button>
</div>
</fieldset>
</form>
</div>
</div>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-17879056-12', 'auto');
ga('send', 'pageview');
</script>
</body>
</html>