Skip to content

Commit 9fa9f49

Browse files
save file
1 parent 0aa7f8f commit 9fa9f49

File tree

1 file changed

+121
-81
lines changed
  • utils/gcloud/generate-token-from-service-account-keyfile

1 file changed

+121
-81
lines changed

utils/gcloud/generate-token-from-service-account-keyfile/generate.js

Lines changed: 121 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -3,85 +3,23 @@
33

44
async function generate(keyfile,scope){
55

6-
7-
6+
var encoder = new TextEncoder();
7+
88
var clientEmail = keyfile.client_email;
9-
var privateKeyPem = keyfile.private_key.replace(/\\n/g,'\n');
9+
var privateKeyPem = keyfile.private_key;
10+
11+
privateKeyPem = norm_key(privateKeyPem);
1012

1113
var assertion = await buildJwtAssertion({clientEmail,privateKeyPem,scope});
12-
var json = await exchangeForAccessToken(assertion);
13-
var token = json.access_token;
14-
14+
var {json,error} = await exchangeForAccessToken(assertion);
15+
if(error){
16+
return {error};
17+
}
1518

19+
var token = json.access_token;
1620
return {json,token};
1721

1822

19-
20-
function base64url(input){
21-
22-
let bytes;
23-
24-
if(typeof input=='string'){
25-
bytes = encoder.encode(input);
26-
}else if(input instanceof ArrayBuffer){
27-
bytes = new Uint8Array(input);
28-
}else if(ArrayBuffer.isView(input)){
29-
bytes = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
30-
}else{
31-
throw new TypeError('Unsupported input');
32-
}
33-
34-
var bin = '';
35-
for(var i=0;i<bytes.length;i++){
36-
37-
bin += String.fromCharCode(bytes[i]);
38-
39-
}//for
40-
41-
var str = btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
42-
return str;
43-
44-
}//base64url
45-
46-
47-
function pemToArrayBuffer(pem){
48-
49-
const b64 = pem.replace(/-----BEGIN [^-]+-----/g, '')
50-
.replace(/-----END [^-]+-----/g, '')
51-
.replace(/\s+/g, '');
52-
const raw = atob(b64);
53-
const buf = new Uint8Array(raw.length);
54-
55-
for(let i=0;i<raw.length;i++){
56-
57-
buf[i] = raw.charCodeAt(i);
58-
59-
}//fpr
60-
61-
return buf.buffer;
62-
63-
}//pem_buf
64-
65-
66-
async function importPkcs8PrivateKey(pem) {
67-
68-
var keyData = pemToArrayBuffer(pem);
69-
var key = await crypto.subtle.importKey('pkcs8',keyData,{name:'RSASSA-PKCS1-v1_5',hash:'SHA-256'},false,['sign']);
70-
return key
71-
72-
}//import
73-
74-
75-
async function signRS256(privateKey, dataToSign) {
76-
77-
var dataBytes = encoder.encode(dataToSign);
78-
var sig = await crypto.subtle.sign({name:'RSASSA-PKCS1-v1_5'},privateKey,dataBytes);
79-
var uint8 = new Uint8Array(sig);
80-
return uint8;
81-
82-
}//sign
83-
84-
8523
async function buildJwtAssertion({clientEmail,privateKeyPem,scope,aud}){
8624

8725
scope = Array.isArray(scope) ? scope.join(' ') : scope;
@@ -95,20 +33,23 @@
9533
var payload = {iss,scope,aud,iat,exp};
9634

9735
var header = {alg:'RS256',typ:'JWT'};
98-
var encodedHeader = base64url(JSON.stringify(header));
99-
var encodedPayload = base64url(JSON.stringify(payload));
36+
var str = JSON.stringify(header);
37+
var encodedHeader = b64url(str);
38+
39+
var str = JSON.stringify(payload);
40+
var encodedPayload = b64url(str);
10041
var unsigned = `${encodedHeader}.${encodedPayload}`;
10142

10243
var key = await importPkcs8PrivateKey(privateKeyPem);
10344
var sig = await signRS256(key,unsigned);
104-
var encodedSig = base64url(sig);
45+
var encodedSig = b64url(sig);
10546
var str = `${unsigned}.${encodedSig}`;
10647
return str
10748

10849
}//build
10950

11051

111-
async function exchangeForAccessToken(assertion) {
52+
async function exchangeForAccessToken(assertion){
11253

11354
var url = 'https://oauth2.googleapis.com/token';
11455
var body = new URLSearchParams({grant_type:'urn:ietf:params:oauth:grant-type:jwt-bearer',assertion});
@@ -127,20 +68,119 @@
12768
}//catch
12869
if(err){
12970
console.error(err);
130-
disp(err.toString());
131-
return;
71+
var error = err.toString();
72+
return {error}
13273
}
13374

13475
if(!res.ok){
135-
throw new Error(`Token exchange failed: ${res.status} ${res.statusText} ${await res.text()}`);
76+
var error = `Token exchange failed: ${res.status} ${res.statusText} ${await res.text()}`;
77+
return {error};
13678
}
13779
// { access_token, token_type, expires_in }
13880
var json = await res.json();
139-
return json;
81+
return {json};
14082

14183
}//exchange
84+
85+
86+
async function importPkcs8PrivateKey(pem){
87+
88+
var buf = pem_buf(pem);
89+
var params = {name:'RSASSA-PKCS1-v1_5',hash:'SHA-256'};
90+
var key = await crypto.subtle.importKey('pkcs8',buf,params,false,['sign']);
91+
return key
92+
93+
}//import
94+
95+
96+
async function signRS256(private,data){
97+
98+
var bytes = encoder.encode(data);
99+
var sig = await crypto.subtle.sign({name:'RSASSA-PKCS1-v1_5'},private,bytes);
100+
var uint8 = new Uint8Array(sig);
101+
return uint8;
102+
103+
}//sign
104+
142105

143-
106+
function norm_key(pem){
107+
108+
pem = pem.replace(/\\n/g,'\n');
109+
return pem;
110+
111+
}//norm
112+
113+
114+
function b64url(input){
115+
116+
var uint8 = _uint8(input);
117+
if(!uint8){
118+
throw new TypeError('Unsupported input');
119+
}
120+
121+
var bin = '';
122+
var n = uint8.length;
123+
for(var i=0;i<n;i++){
124+
125+
var byte = uint8[i];
126+
bin += String.fromCharCode(byte);
127+
128+
}//for
129+
130+
var b64 = btoa(bin);
131+
b64 = b64.replaceAll('+','-');
132+
b64 = b64.replaceAll('/','_');
133+
b64 = b64.replaceAll('=','');
134+
135+
var url = b64;
136+
return url;
137+
138+
}//b64url
139+
140+
141+
function _uint8(input){
142+
143+
var uint8;
144+
if(typeof input=='string'){
145+
uint8 = encoder.encode(input);
146+
}
147+
if(input instanceof ArrayBuffer){
148+
uint8 = new Uint8Array(input);
149+
}
150+
if(ArrayBuffer.isView(input)){
151+
uint8 = new Uint8Array(input.buffer,input.byteOffset,input.byteLength);
152+
}
153+
return uint8;
154+
155+
}//to_uint8
156+
157+
158+
function pem_buf(pem){
159+
160+
var i1 = pem.indexOf('\n');
161+
var i2 = pem.lastIndexOf('\n');
162+
var s = pem.slice(i1+1,i2);
163+
var b64 = pem.replaceAll('\n','');
164+
/*
165+
var b64 = pem.replace(/-----BEGIN [^-]+-----/g,'')
166+
.replace(/-----END [^-]+-----/g,'')
167+
.replace(/\s+/g,'');
168+
*/
169+
var bin = atob(b64);
170+
var n = bin.length;
171+
var uint8 = new Uint8Array(n);
172+
173+
for(var i=0;i<n;i++){
174+
175+
uint8[i] = bin.charCodeAt(i);
176+
177+
}//fpr
178+
179+
var buf = uint8.buffer;
180+
return buf;
181+
182+
}//pem_buf
183+
144184
}//generate
145185

146186

0 commit comments

Comments
 (0)