Skip to content

Commit 72a8777

Browse files
save file
1 parent 14440f5 commit 72a8777

File tree

1 file changed

+89
-206
lines changed

1 file changed

+89
-206
lines changed

utils/gcloud/generate-token-from-service-account-keyfile/v2.0/generate-token-from-service-account-keyfile-v2.0.html

Lines changed: 89 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@
3939

4040
<script src='https://ajaxorg.github.io/ace-builds/src-noconflict/ace.js'></script>
4141

42+
<!--
4243
<script src='generate.js'></script>
44+
-->
4345

4446

4547
<script src='https://libs.ext-code.com/js/dom/component/component.js'></script>
@@ -183,13 +185,16 @@ <h1 class=visually-hidden>generate access token from service account keyfile</h1
183185

184186

185187
<script>
186-
187-
var encoder = new TextEncoder();
188188

189-
189+
190190
var keyfile;
191191
var token;
192+
193+
var scope = 'https://www.googleapis.com/auth/devstorage.read_write';
194+
192195

196+
var btn = {};
197+
193198

194199
function initdom(){
195200

@@ -199,234 +204,95 @@ <h1 class=visually-hidden>generate access token from service account keyfile</h1
199204
log.initdom();
200205

201206

202-
document.querySelector('[value=copy]').onclick = e=>{
207+
$('[value=copy]').onclick = btn.copy;
208+
$('[value=new]').onclick = btn.new;
203209

204-
if(!token){
205-
disp('no token');
206-
return;
207-
}
208-
navigator.clipboard.writeText(token);
209-
disp('token copied');
210-
211-
}//copy
212-
213-
214-
document.querySelector('[value=new]').onclick = async e=>{
215210

216-
if(!keyfile){
217-
disp('no service account file selected');
218-
return;
219-
}
211+
file.onchange = onchange;
220212

221213

222-
223-
output.replaceChildren();
224-
225-
var json;
226-
({json,token} = await generate(keyfile));
214+
215+
}//initdom
216+
227217

218+
//:
219+
220+
221+
btn.copy = function(){
222+
223+
if(!token){
224+
disp('no token');
225+
return;
226+
}
227+
navigator.clipboard.writeText(token);
228+
disp('token copied');
228229

229-
disp(JSON.stringify(json,null,4));
230-
231-
disp();
232-
233-
disp('token');
234-
disp(token);
235-
236-
disp();
237-
238-
navigator.clipboard.writeText(token);
239-
disp('copied to clipboard');
240-
241-
242-
}//new
230+
}//copy
231+
232+
233+
btn.new = async function(){
243234

235+
if(!keyfile){
236+
disp('no service account file');
237+
return;
238+
}
239+
create();
244240

245-
file.onchange = async function(){
246-
247-
var blob = file.files[0];
248-
var txt = await blob.text();
249-
keyfile = JSON.parse(txt);
250-
251-
252-
output.replaceChildren();
253-
254-
255-
var {json,token} = await generate(keyfile);
241+
}//new
256242

257243

258-
disp(JSON.stringify(json,null,4));
259-
260-
disp();
261-
262-
disp('token');
263-
disp(token);
264-
265-
disp();
266-
267-
navigator.clipboard.writeText(token);
268-
disp('copied to clipboard');
269-
270-
271-
}//onchange
272-
273-
274-
275-
}//initdom
276-
244+
async function onchange(){
245+
246+
var blob = file.files[0];
247+
var txt = await blob.text();
248+
keyfile = JSON.parse(txt);
249+
create();
250+
251+
}//onchange
252+
277253

278254
//:
279255

280256

281-
282-
/*
283-
284-
285-
async function generate(keyfile){
257+
async function create(){
258+
259+
output.replaceChildren();
286260

287-
288-
289-
var clientEmail = keyfile.client_email;
290-
var privateKeyPem = keyfile.private_key.replace(/\\n/g,'\n');
291-
var scope = 'https://www.googleapis.com/auth/devstorage.read_write';
261+
gen();
292262

293-
var assertion = await buildJwtAssertion({clientEmail,privateKeyPem,scope});
294-
var json = await exchangeForAccessToken(assertion);
295-
var token = json.access_token;
263+
var {json,error} = await generate(keyfile,scope);
296264

265+
if(error){
266+
disp.error(error);
267+
return;
268+
}
297269

298-
return {json,token};
299-
300-
301-
302-
function base64url(input){
303-
304-
let bytes;
305-
306-
if(typeof input=='string'){
307-
bytes = encoder.encode(input);
308-
}else if(input instanceof ArrayBuffer){
309-
bytes = new Uint8Array(input);
310-
}else if(ArrayBuffer.isView(input)){
311-
bytes = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
312-
}else{
313-
throw new TypeError('Unsupported input');
314-
}
315-
316-
var bin = '';
317-
for(var i=0;i<bytes.length;i++){
318-
319-
bin += String.fromCharCode(bytes[i]);
320-
321-
}//for
322-
323-
var str = btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
324-
return str;
325-
326-
}//base64url
327-
328-
329-
function pemToArrayBuffer(pem){
330-
331-
const b64 = pem.replace(/-----BEGIN [^-]+-----/g, '')
332-
.replace(/-----END [^-]+-----/g, '')
333-
.replace(/\s+/g, '');
334-
const raw = atob(b64);
335-
const buf = new Uint8Array(raw.length);
336-
337-
for(let i=0;i<raw.length;i++){
338-
339-
buf[i] = raw.charCodeAt(i);
340-
341-
}//fpr
342-
343-
return buf.buffer;
344-
345-
}//pem_buf
346-
347-
348-
async function importPkcs8PrivateKey(pem) {
270+
token = json.access_token;
271+
272+
349273

350-
var keyData = pemToArrayBuffer(pem);
351-
var key = await crypto.subtle.importKey('pkcs8',keyData,{name:'RSASSA-PKCS1-v1_5',hash:'SHA-256'},false,['sign']);
352-
return key
353-
354-
}//import
355-
356-
357-
async function signRS256(privateKey, dataToSign) {
274+
disp.json(json);
358275

359-
var dataBytes = encoder.encode(dataToSign);
360-
var sig = await crypto.subtle.sign({name:'RSASSA-PKCS1-v1_5'},privateKey,dataBytes);
361-
var uint8 = new Uint8Array(sig);
362-
return uint8;
363-
364-
}//sign
365-
366-
367-
async function buildJwtAssertion({clientEmail,privateKeyPem,scope,aud='https://oauth2.googleapis.com/token'}){
276+
disp();
368277

369-
var key = await importPkcs8PrivateKey(privateKeyPem);
370-
371-
var now = Math.floor(Date.now()/1000);
372-
var header = {alg:'RS256',typ:'JWT'};
373-
var payload = {
374-
iss : clientEmail,
375-
scope : Array.isArray(scope) ? scope.join(' ') : scope,
376-
aud : aud,
377-
iat : now,
378-
exp : now+3600, // 1 hour max
379-
};
380-
381-
var encodedHeader = base64url(JSON.stringify(header));
382-
var encodedPayload = base64url(JSON.stringify(payload));
383-
var unsigned = `${encodedHeader}.${encodedPayload}`;
384-
385-
var sig = await signRS256(key,unsigned);
386-
var encodedSig = base64url(sig);
387-
var str = `${unsigned}.${encodedSig}`;
388-
return str
389-
390-
}//build
391-
278+
disp('token');
279+
disp(token);
392280

393-
async function exchangeForAccessToken(assertion) {
281+
disp();
394282

395-
var url = 'https://oauth2.googleapis.com/token';
396-
var body = new URLSearchParams({grant_type:'urn:ietf:params:oauth:grant-type:jwt-bearer',assertion});
397-
var headers = {'Content-Type':'application/x-www-form-urlencoded'};
398-
399-
var err;
400-
try{
401-
402-
var res = await fetch(url,{method:'post',headers,body});
403-
404-
}//try
405-
catch(err2){
406-
407-
err = err2;
408-
409-
}//catch
410-
if(err){
411-
console.error(err);
412-
disp(err.toString());
413-
return;
414-
}
415-
416-
if(!res.ok){
417-
throw new Error(`Token exchange failed: ${res.status} ${res.statusText} ${await res.text()}`);
418-
}
419-
// { access_token, token_type, expires_in }
420-
var json = await res.json();
421-
return json;
422-
423-
}//exchange
424-
283+
navigator.clipboard.writeText(token);
284+
disp('copied to clipboard');
285+
286+
}//create
425287

426-
}//generate
427-
288+
289+
function gen(){
290+
291+
var txt = script.getvalue();
292+
window.eval(txt);
293+
294+
}//gen
428295

429-
*/
430296

431297
function disp(){
432298

@@ -439,8 +305,25 @@ <h1 class=visually-hidden>generate access token from service account keyfile</h1
439305
output.append(div);
440306

441307
output.scrollTop = output.scrollHeight;
308+
return div;
442309

443310
}//disp
311+
312+
313+
disp.error = function(){
314+
315+
var div = disp.apply(null,arguments);
316+
div.style.color = 'red';
317+
318+
}//error
319+
320+
321+
disp.json = function(v){
322+
323+
var str = JSON.stringify(v,null,4);
324+
disp(str);
325+
326+
}//json
444327

445328

446329

0 commit comments

Comments
 (0)