Reputation: 839
I'm building Google App Script product that uploads pdf file to Google Cloud Storage and it worked very well (thanks to this tutorial). But I'm unable to get uploaded file URL.
This is my uploadFileToGCS()
function:
function uploadFileToGCS() {
var service = getService();
if (!service.hasAccess()) {
Logger.log("Please authorize %s", service.getAuthorizationUrl());
return;
}
var blob = DriveApp.getFileById(params.DRIVE_FILE).getBlob();
var bytes = blob.getBytes();
var url = 'https://www.googleapis.com/upload/storage/v1/b/BUCKET/o?uploadType=media&name=FILE'
.replace("BUCKET", params.BUCKET_NAME)
.replace("FILE", encodeURIComponent(params.FILE_PATH));
var response = UrlFetchApp.fetch(url, {
method: "POST",
contentLength: bytes.length,
contentType: blob.getContentType(),
payload: bytes,
headers: {
Authorization: 'Bearer ' + service.getAccessToken()
}
});
var result = JSON.parse(response.getContentText());
Logger.log(JSON.stringify(result, null, 2));
}
And the log of response: Logger.log(JSON.stringify(result, null, 2));
19-05-29 21:28:19:726 PDT] {
"kind": "storage#object",
"id": "bucket_name/folder_name/file_name.pdf/1559190499625016",
"selfLink": "https://www.googleapis.com/storage/v1/b/bucket_name/o/folder_name/file_name.pdf",
"name": "folder_name/file_name.pdf",
"bucket": "bucket_name",
"generation": "1559190499625016",
"metageneration": "1",
"contentType": "application/pdf",
"timeCreated": "2019-05-30T04:28:19.624Z",
"updated": "2019-05-30T04:28:19.624Z",
"storageClass": "MULTI_REGIONAL",
"timeStorageClassUpdated": "2019-05-30T04:28:19.624Z",
"size": "101396",
"md5Hash": "hash",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/bucket_name/o/folder_name/file_name.pdf?generation=1559190499625016&alt=media",
}
when I click to mediaLink
, the browser automatically downloads my pdf file, that's not I want.
So how I can get uploaded URL file from Google Cloud Storage by GAS ? Any advice is welcome!
Upvotes: 1
Views: 2301
Reputation: 4786
The tutorial from @zkohi's answer is outdated and did not work for me. I took the sample code from https://cloud.google.com/storage/docs/access-control/signing-urls-manually and rewrote it in JavaScript.
function generate_signed_url(google_credentials, bucket_name, object_name,
subresource, expiration, http_method,
query_parameters, headers)
{
if (expiration === undefined) expiration = 604800;
if (http_method === undefined) http_method = 'GET';
if (expiration > 604800) {
throw new Error('Expiration Time can\'t be longer than 604800 seconds (7 days).');
}
var escaped_object_name = encodeURIComponent(object_name).replace(/%2[fF]/g, '/');
var canonical_uri = '/' + escaped_object_name;
var datetime_now = new Date();
var request_timestamp = datetime_now.toISOString().replace(/\.\d\d\dZ$/, 'Z').replace(/[-:]/g, '');
var datestamp = datetime_now.toISOString().replace(/^(\d{4})-(\d\d)-(\d\d).*$/, '$1$2$3')
var client_email = google_credentials.client_email;
var credential_scope = datestamp + '/auto/storage/goog4_request';
var credential = client_email + '/' + credential_scope;
if (headers === undefined) headers = {};
var host = bucket_name + '.storage.googleapis.com';
headers['host'] = host;
var ordered_headers = Object.entries(headers);
ordered_headers.sort();
var canonical_headers = ordered_headers.map(([k, v]) => k.toLowerCase() + ':' + v.toLowerCase() + '\n').join('');
var signed_headers = ordered_headers.map(([k]) => k.toLowerCase()).join(';');
if (query_parameters === undefined) query_parameters = {};
query_parameters['X-Goog-Algorithm'] = 'GOOG4-RSA-SHA256';
query_parameters['X-Goog-Credential'] = credential;
query_parameters['X-Goog-Date'] = request_timestamp;
query_parameters['X-Goog-Expires'] = expiration;
query_parameters['X-Goog-SignedHeaders'] = signed_headers;
if (subresource !== undefined) {
query_parameters[subresource] = '';
}
var ordered_query_parameters = Object.entries(query_parameters);
ordered_query_parameters.sort();
var canonical_query_string = ordered_query_parameters.map(([k, v]) => encodeURIComponent(k) + '=' + encodeURIComponent(v)).join('&');
var canonical_request = [http_method,
canonical_uri,
canonical_query_string,
canonical_headers,
signed_headers,
'UNSIGNED-PAYLOAD'].join('\n');
var canonical_request_hash = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, canonical_request)
.map(byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
var string_to_sign = ['GOOG4-RSA-SHA256',
request_timestamp,
credential_scope,
canonical_request_hash].join('\n');
var signature = Utilities.computeRsaSha256Signature(string_to_sign, google_credentials.private_key)
.map(byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
var scheme_and_host = 'https://' + host;
var signed_url = scheme_and_host + canonical_uri + '?' + canonical_query_string + '&x-goog-signature=' + signature;
return signed_url
}
Upvotes: 1
Reputation: 2520
The tutorial is https://medium.com/google-cloud/google-cloud-storage-signed-urls-in-apps-script-161b74a9c5e7 .
And The docs to create a service account key using the GCP Console is https://cloud.google.com/iam/docs/creating-managing-service-account-keys .
Upvotes: 1