1/* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import {FunctionUtils} from 'common/function_utils'; 18import { 19 BuganizerAttachmentsDownloadEmitter, 20 OnBuganizerAttachmentsDownloaded, 21 OnBuganizerAttachmentsDownloadStart, 22} from 'interfaces/buganizer_attachments_download_emitter'; 23import {MessageType, OpenBuganizerResponse, OpenRequest, WebCommandMessage} from './messages'; 24 25export class AbtChromeExtensionProtocol implements BuganizerAttachmentsDownloadEmitter { 26 static readonly ABT_EXTENSION_ID = 'mbbaofdfoekifkfpgehgffcpagbbjkmj'; 27 private onAttachmentsDownloadStart: OnBuganizerAttachmentsDownloadStart = 28 FunctionUtils.DO_NOTHING; 29 private onAttachmentsDownloaded: OnBuganizerAttachmentsDownloaded = 30 FunctionUtils.DO_NOTHING_ASYNC; 31 32 setOnBuganizerAttachmentsDownloadStart(callback: OnBuganizerAttachmentsDownloadStart) { 33 this.onAttachmentsDownloadStart = callback; 34 } 35 36 setOnBuganizerAttachmentsDownloaded(callback: OnBuganizerAttachmentsDownloaded) { 37 this.onAttachmentsDownloaded = callback; 38 } 39 40 run() { 41 const urlParams = new URLSearchParams(window.location.search); 42 if (urlParams.get('source') !== 'openFromExtension' || !chrome) { 43 return; 44 } 45 46 this.onAttachmentsDownloadStart(); 47 48 const openRequestMessage: OpenRequest = { 49 action: MessageType.OPEN_REQUEST, 50 }; 51 52 chrome.runtime.sendMessage( 53 AbtChromeExtensionProtocol.ABT_EXTENSION_ID, 54 openRequestMessage, 55 async (message) => await this.onMessageReceived(message) 56 ); 57 } 58 59 private async onMessageReceived(message: WebCommandMessage) { 60 if (this.isOpenBuganizerResponseMessage(message)) { 61 await this.onOpenBuganizerResponseMessageReceived(message); 62 } else { 63 console.warn('ABT chrome extension protocol received unexpected message:', message); 64 } 65 } 66 67 private async onOpenBuganizerResponseMessageReceived(message: OpenBuganizerResponse) { 68 console.log('ABT chrome extension protocol received OpenBuganizerResponse message:', message); 69 70 if (message.attachments.length === 0) { 71 console.warn('ABT chrome extension protocol received no attachments'); 72 } 73 74 const filesBlobPromises = message.attachments.map(async (attachment) => { 75 const fileQueryResponse = await fetch(attachment.objectUrl); 76 const blob = await fileQueryResponse.blob(); 77 78 // Note: the received blob's media type is wrong. It is always set to "image/png". 79 // Context: http://google3/javascript/closure/html/safeurl.js?g=0&l=256&rcl=273756987 80 // Cloning the blob clears the media type. 81 const file = new File([blob], attachment.name); 82 83 return file; 84 }); 85 86 const files = await Promise.all(filesBlobPromises); 87 await this.onAttachmentsDownloaded(files); 88 } 89 90 private isOpenBuganizerResponseMessage( 91 message: WebCommandMessage 92 ): message is OpenBuganizerResponse { 93 return message.action === MessageType.OPEN_BUGANIZER_RESPONSE; 94 } 95} 96