All files / Scripts/ui/getHeaders GetHeadersRest.ts

11.11% Statements 8/72
0% Branches 0/26
0% Functions 0/9
11.26% Lines 8/71

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 1799x   9x 9x 9x 9x 9x                           9x 9x                                                                                                                                                                                                                                                                                                                          
import { jwtDecode } from "jwt-decode";
 
import { GetHeaders } from "./GetHeaders";
import { diagnostics } from "../../Diag";
import { Errors } from "../../Errors";
import { mhaStrings } from "../../mhaStrings";
import { ParentFrame } from "../../ParentFrame";
 
/*
 * GetHeadersRest.js
 *
 * This file has all the methods to get PR_TRANSPORT_MESSAGE_HEADERS
 * from the current message via REST.
 *
 * Requirement Sets and Permissions
 * getCallbackTokenAsync requires 1.5 and ReadItem
 * convertToRestId requires 1.3 and Restricted
 * restUrl requires 1.5 and ReadItem
 */
 
export class GetHeadersRest {
    private static minRestSet = "1.5";
 
    public static canUseRest(): boolean { return GetHeaders.canUseAPI("Rest", GetHeadersRest.minRestSet); }
 
    private static getItemRestId(): string {
        Iif (!Office.context.mailbox.item) return "";
        // Currently the only Outlook Mobile version that supports add-ins
        // is Outlook for iOS.
        if (Office.context.mailbox.diagnostics.hostName === "OutlookIOS") {
            // itemId is already REST-formatted
            return Office.context.mailbox.item.itemId;
        } else {
            // Convert to an item ID for API v2.0
            return Office.context.mailbox.convertToRestId(
                Office.context.mailbox.item.itemId,
                Office.MailboxEnums.RestVersion.v2_0
            );
        }
    }
 
    private static getBaseUrl(url: string): string {
        const parts = url.split("/");
 
        return parts[0] + "//" + parts[2];
    }
 
    private static getRestUrl(accessToken: string): string {
        // Shim function to workaround
        // mailbox.restUrl == null case
        Iif (Office.context.mailbox.restUrl) {
            return GetHeadersRest.getBaseUrl(Office.context.mailbox.restUrl);
        }
 
        // parse the token
        const jwt = jwtDecode(accessToken);
 
        // 'aud' parameter from token can be in a couple of
        // different formats.
        const aud = Array.isArray(jwt.aud) ? jwt.aud[0] : jwt.aud;
 
        Iif (aud) {
            // Format 1: It's just the URL
            Iif (aud.match(/https:\/\/([^@]*)/)) {
                return aud;
            }
 
            // Format 2: GUID/hostname@GUID
            const match = aud.match(/\/([^@]*)@/);
            Iif (match && match[1]) {
                return "https://" + match[1];
            }
        }
 
        // Couldn't find what we expected, default to
        // outlook.office.com
        return "https://outlook.office.com";
    }
 
    private static async getHeaders(accessToken: string): Promise<string> {
        Iif (!accessToken || accessToken === "") {
            Errors.logMessage("No access token?");
            return "";
        }
 
        Iif (!Office.context.mailbox.item) {
            Errors.logMessage("No item");
            return "";
        }
 
        Iif (!Office.context.mailbox.item.itemId) {
            Errors.logMessage("No itemId");
            return "";
        }
 
        // Get the item's REST ID
        const itemId = GetHeadersRest.getItemRestId();
 
        const getMessageUrl = GetHeadersRest.getRestUrl(accessToken) +
            "/api/v2.0/me/messages/" +
            itemId +
            // PR_TRANSPORT_MESSAGE_HEADERS
            "?$select=SingleValueExtendedProperties&$expand=SingleValueExtendedProperties($filter=PropertyId eq 'String 0x007D')";
 
        try{
            const response = await fetch(getMessageUrl, {
                headers: {
                    "Authorization": "Bearer " + accessToken, //eslint-disable-line @typescript-eslint/naming-convention
                    "Accept": "application/json; odata.metadata=none" //eslint-disable-line @typescript-eslint/naming-convention
                }
            });
 
            Iif (!response.ok) {
                diagnostics.set("getHeadersFailure", JSON.stringify(response));
                if (response.status === 0) {
                    // Fallback to EWS now
                } else Iif (response.status === 404) {
                    ParentFrame.showError(null, mhaStrings.mhaMessageMissing, true);
                }
 
                return "";
            }
 
            const item = await response.json();
 
            if (item.SingleValueExtendedProperties !== undefined) {
                return item.SingleValueExtendedProperties[0].Value;
            } else {
                ParentFrame.showError(null, mhaStrings.mhaHeadersMissing, true);
                return "";
            }
        }
        catch (e) {
            ParentFrame.showError(e, "Failed parsing headers");
        }
 
        return "";
    }
 
    private static async getCallbackToken(): Promise<string> {
        return new Promise((resolve) => {
            Office.context.mailbox.getCallbackTokenAsync((result) => {
                if (result.status === Office.AsyncResultStatus.Succeeded) {
                    resolve(result.value);
                } else {
                    diagnostics.set("callbackTokenFailure", JSON.stringify(result));
                    Errors.log(result.error, "Unable to obtain callback token.\nFallback to EWS.\n" + JSON.stringify(result, null, 2), true);
                    resolve("");
                }
            });
        });
    }
 
    public static async send(): Promise<string> {
        Iif (!GetHeaders.validItem()) {
            Errors.logMessage("No item selected (REST)");
            return "";
        }
 
        Iif (!GetHeadersRest.canUseRest()) {
            return "";
        }
 
        ParentFrame.updateStatus(mhaStrings.mhaRequestSent);
 
        try {
            const accessToken= await GetHeadersRest.getCallbackToken();
            const headers = await GetHeadersRest.getHeaders(accessToken);
 
            return headers;
        }
        catch (e) {
            ParentFrame.showError(e, "Failed using getCallbackTokenAsync");
        }
 
        return "";
    }
}