UNPKG

office-addin-dev-settings

Version:

Configure developer settings for Office Add-ins.

366 lines 17.5 kB
"use strict"; // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. Object.defineProperty(exports, "__esModule", { value: true }); exports.sideloadAddIn = exports.getTemplatePath = exports.generateSideloadUrl = exports.generateSideloadFile = void 0; const tslib_1 = require("tslib"); const fs_1 = tslib_1.__importDefault(require("fs")); const adm_zip_1 = tslib_1.__importDefault(require("adm-zip")); const office_addin_manifest_1 = require("office-addin-manifest"); const open = require("open"); const semver = require("semver"); const os_1 = tslib_1.__importDefault(require("os")); const path_1 = tslib_1.__importDefault(require("path")); const appType_1 = require("./appType"); const dev_settings_1 = require("./dev-settings"); const process_1 = require("./process"); const prompt_1 = require("./prompt"); const registry = tslib_1.__importStar(require("./registry")); const defaults_1 = require("./defaults"); const office_addin_usage_data_1 = require("office-addin-usage-data"); /* global Buffer console process URL __dirname */ /** * Create an Office document in the temporary files directory * which can be opened to launch the Office app and load the add-in. * @param app Office app * @param manifest Manifest for the add-in. * @returns Path to the file. */ function generateSideloadFile(app, manifest, document) { return tslib_1.__awaiter(this, void 0, void 0, function* () { if (!manifest.id) { throw new office_addin_usage_data_1.ExpectedError("The manifest does not contain the id for the add-in."); } if (!manifest.officeAppType) { throw new office_addin_usage_data_1.ExpectedError("The manifest does not contain the OfficeApp xsi:type."); } if (!manifest.version) { throw new office_addin_usage_data_1.ExpectedError("The manifest does not contain the version for the add-in."); } const addInType = (0, office_addin_manifest_1.getAddInTypeForManifestOfficeAppType)(manifest.officeAppType); if (!addInType) { throw new office_addin_usage_data_1.ExpectedError("The manifest contains an unsupported OfficeApp xsi:type."); } const documentWasProvided = document && document !== ""; const templatePath = documentWasProvided ? path_1.default.resolve(document) : getTemplatePath(app, addInType); if (!templatePath) { throw new office_addin_usage_data_1.ExpectedError(`Sideload is not supported for apptype: ${addInType}.`); } const appName = (0, office_addin_manifest_1.getOfficeAppName)(app); const extension = path_1.default.extname(templatePath); const pathToWrite = makePathUnique(path_1.default.join(os_1.default.tmpdir(), `${appName} add-in ${manifest.id}${extension}`), true); if (!documentWasProvided) { const webExtensionPath = getWebExtensionPath(app, addInType); if (!webExtensionPath) { throw new office_addin_usage_data_1.ExpectedError("Don't know the webextension path."); } // replace the placeholder id and version const templateZip = new adm_zip_1.default(templatePath); const outZip = new adm_zip_1.default(); const extEntry = templateZip.getEntry(webExtensionPath); if (!extEntry) { throw new office_addin_usage_data_1.ExpectedError("webextension was not found."); } const webExtensionXml = templateZip .readAsText(extEntry) .replace(/00000000-0000-0000-0000-000000000000/g, manifest.id) .replace(/1.0.0.0/g, manifest.version); const webExtensionFolderPath = webExtensionPath.substring(0, webExtensionPath.lastIndexOf("/")); templateZip.getEntries().forEach(function (entry) { var data = entry.getData(); if (entry == extEntry && manifest.manifestType == office_addin_manifest_1.ManifestType.XML) { data = Buffer.from(webExtensionXml); } // If manifestType is JSON, remove the web extension folder if (!entry.entryName.startsWith(webExtensionFolderPath) || manifest.manifestType !== office_addin_manifest_1.ManifestType.JSON) { outZip.addFile(entry.entryName, data, entry.comment, entry.attr); } }); // Write the file yield outZip.writeZipPromise(pathToWrite); } else { yield fs_1.default.promises.copyFile(templatePath, pathToWrite); } return pathToWrite; }); } exports.generateSideloadFile = generateSideloadFile; /** * Create an Office document url with query params which can be opened * to register an Office add-in in Office Online. * @param manifestPath Path to the manifest file for the Office Add-in. * @param documentUrl Office Online document url * @param isTest Indicates whether to append test query param to suppress Office Online dialogs. * @returns Document url with query params appended. */ function generateSideloadUrl(manifestFileName, manifest, documentUrl, isTest = false) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const testQueryParam = "&wdaddintest=true"; if (!manifest.id) { throw new office_addin_usage_data_1.ExpectedError("The manifest does not contain the id for the add-in."); } if (manifest.defaultSettings === undefined || manifest.defaultSettings.sourceLocation === undefined) { throw new office_addin_usage_data_1.ExpectedError("The manifest does not contain the SourceLocation for the add-in"); } const sourceLocationUrl = new URL(manifest.defaultSettings.sourceLocation); if (sourceLocationUrl.protocol.indexOf("https") === -1) { throw new office_addin_usage_data_1.ExpectedError("The SourceLocation in the manifest does not use the HTTPS protocol."); } if (sourceLocationUrl.host.indexOf("localhost") === -1 && sourceLocationUrl.host.indexOf("127.0.0.1") === -1) { throw new office_addin_usage_data_1.ExpectedError("The hostname specified by the SourceLocation in the manifest is not supported for sideload. The hostname should be 'localhost' or 127.0.0.1."); } let queryParms = `&wdaddindevserverport=${sourceLocationUrl.port}&wdaddinmanifestfile=${manifestFileName}&wdaddinmanifestguid=${manifest.id}`; if (isTest) { queryParms = `${queryParms}${testQueryParam}`; } return `${documentUrl}${queryParms}`; }); } exports.generateSideloadUrl = generateSideloadUrl; /** * Returns the path to the document used as a template for sideloading, * or undefined if sideloading is not supported. * @param app Specifies the Office app. * @param addInType Specifies the type of add-in. */ function getTemplatePath(app, addInType) { switch (app) { case office_addin_manifest_1.OfficeApp.Excel: switch (addInType) { case office_addin_manifest_1.AddInType.Content: return path_1.default.resolve(__dirname, "../templates/ExcelWorkbookWithContent.xlsx"); case office_addin_manifest_1.AddInType.TaskPane: return path_1.default.resolve(__dirname, "../templates/ExcelWorkbookWithTaskPane.xlsx"); } break; case office_addin_manifest_1.OfficeApp.PowerPoint: switch (addInType) { case office_addin_manifest_1.AddInType.Content: return path_1.default.resolve(__dirname, "../templates/PowerPointPresentationWithContent.pptx"); case office_addin_manifest_1.AddInType.TaskPane: return path_1.default.resolve(__dirname, "../templates/PowerPointPresentationWithTaskPane.pptx"); } break; case office_addin_manifest_1.OfficeApp.Word: switch (addInType) { case office_addin_manifest_1.AddInType.TaskPane: return path_1.default.resolve(__dirname, "../templates/WordDocumentWithTaskPane.docx"); } break; } } exports.getTemplatePath = getTemplatePath; /** * Returns the web extension path in the sideload document. * @param app Specifies the Office app. * @param addInType Specifies the type of add-in. */ function getWebExtensionPath(app, addInType) { switch (app) { case office_addin_manifest_1.OfficeApp.Excel: return "xl/webextensions/webextension.xml"; case office_addin_manifest_1.OfficeApp.PowerPoint: switch (addInType) { case office_addin_manifest_1.AddInType.Content: return "ppt/slides/udata/data.xml"; case office_addin_manifest_1.AddInType.TaskPane: return "ppt/webextensions/webextension.xml"; } break; case office_addin_manifest_1.OfficeApp.Word: return "word/webextensions/webextension.xml"; } } function isSideloadingSupportedForDesktopHost(app) { if (app === office_addin_manifest_1.OfficeApp.Excel || (app === office_addin_manifest_1.OfficeApp.Outlook && process.platform === "win32") || app === office_addin_manifest_1.OfficeApp.PowerPoint || app === office_addin_manifest_1.OfficeApp.Word) { return true; } return false; } function isSideloadingSupportedForWebHost(app) { if (app === office_addin_manifest_1.OfficeApp.Excel || app === office_addin_manifest_1.OfficeApp.PowerPoint || app === office_addin_manifest_1.OfficeApp.Project || app === office_addin_manifest_1.OfficeApp.Word) { return true; } return false; } function hasOfficeVersion(targetVersion, currentVersion) { return semver.gte(currentVersion, targetVersion); } function getOutlookVersion() { return tslib_1.__awaiter(this, void 0, void 0, function* () { try { const key = new registry.RegistryKey(`HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Office\\ClickToRun\\Configuration`); const outlookInstallVersion = yield registry.getStringValue(key, "ClientVersionToReport"); const outlookSmallerVersion = outlookInstallVersion === null || outlookInstallVersion === void 0 ? void 0 : outlookInstallVersion.split(`.`, 3).join(`.`); return outlookSmallerVersion; } catch (_a) { return undefined; } }); } function getOutlookExePath() { return tslib_1.__awaiter(this, void 0, void 0, function* () { try { const OutlookInstallPathRegistryKey = `HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\OUTLOOK.EXE`; const key = new registry.RegistryKey(`${OutlookInstallPathRegistryKey}`); const outlookExePath = yield registry.getStringValue(key, ""); if (!outlookExePath) { throw new Error("Outlook.exe registry empty"); } return outlookExePath; } catch (err) { const errorMessage = `Unable to find Outlook install location: \n${err}`; throw new Error(errorMessage); } }); } /** * Given a file path, returns a unique file path where the file doesn't exist by * appending a period and a numeric suffix, starting from 2. * @param tryToDelete If true, first try to delete the file if it exists. */ function makePathUnique(originalPath, tryToDelete = false) { let currentPath = originalPath; let parsedPath = null; let suffix = 1; while (fs_1.default.existsSync(currentPath)) { let deleted = false; if (tryToDelete) { try { fs_1.default.unlinkSync(currentPath); deleted = true; } catch (_a) { // no error (file is in use) } } if (!deleted) { ++suffix; if (parsedPath == null) { parsedPath = path_1.default.parse(originalPath); } currentPath = path_1.default.join(parsedPath.dir, `${parsedPath.name}.${suffix}${parsedPath.ext}`); } } return currentPath; } /** * Starts the Office app and loads the Office Add-in. * @param manifestPath Path to the manifest file for the Office Add-in. * @param app Office app to launch. * @param canPrompt */ function sideloadAddIn(manifestPath, app, canPrompt = false, appType, document, registration) { return tslib_1.__awaiter(this, void 0, void 0, function* () { try { if (appType === undefined) { appType = appType_1.AppType.Desktop; } const manifest = yield office_addin_manifest_1.OfficeAddinManifest.readManifestFile(manifestPath); const appsInManifest = (0, office_addin_manifest_1.getOfficeAppsForManifestHosts)(manifest.hosts); if (app) { if (appsInManifest.indexOf(app) < 0) { throw new office_addin_usage_data_1.ExpectedError(`The Office Add-in manifest does not support ${(0, office_addin_manifest_1.getOfficeAppName)(app)}.`); } } else { switch (appsInManifest.length) { case 0: throw new office_addin_usage_data_1.ExpectedError("The manifest does not support any Office apps."); case 1: app = appsInManifest[0]; break; default: if (canPrompt) { app = yield (0, prompt_1.chooseOfficeApp)(appsInManifest); } break; } } if (!app) { throw new office_addin_usage_data_1.ExpectedError("Please specify the Office app."); } switch (appType) { case appType_1.AppType.Desktop: yield (0, dev_settings_1.registerAddIn)(manifestPath, registration); yield launchDesktopApp(app, manifest, document); break; case appType_1.AppType.Web: { if (!document) { throw new office_addin_usage_data_1.ExpectedError(`For sideload to web, you need to specify a document url.`); } yield launchWebApp(app, manifestPath, manifest, document); break; } default: throw new office_addin_usage_data_1.ExpectedError("Sideload is not supported for the specified app type."); } defaults_1.usageDataObject.reportSuccess("sideloadAddIn()"); } catch (err) { defaults_1.usageDataObject.reportException("sideloadAddIn()", err); throw err; } }); } exports.sideloadAddIn = sideloadAddIn; function launchDesktopApp(app, manifest, document) { return tslib_1.__awaiter(this, void 0, void 0, function* () { if (!isSideloadingSupportedForDesktopHost(app)) { throw new office_addin_usage_data_1.ExpectedError(`Sideload to the ${(0, office_addin_manifest_1.getOfficeAppName)(app)} app is not supported.`); } // for Outlook, open Outlook.exe; for other Office apps, open the document if (app == office_addin_manifest_1.OfficeApp.Outlook) { const version = yield getOutlookVersion(); if (version && !hasOfficeVersion("16.0.13709", version)) { throw new office_addin_usage_data_1.ExpectedError(`The current version of Outlook does not support sideload. Please use version 16.0.13709 or greater.`); } yield launchApp(app, yield getOutlookExePath()); } else { yield launchApp(app, yield generateSideloadFile(app, manifest, document)); } }); } function launchWebApp(app, manifestPath, manifest, document) { return tslib_1.__awaiter(this, void 0, void 0, function* () { if (!isSideloadingSupportedForWebHost(app)) { throw new office_addin_usage_data_1.ExpectedError(`Sideload to the ${(0, office_addin_manifest_1.getOfficeAppName)(app)} web app is not supported.`); } const manifestFileName = path_1.default.basename(manifestPath); const isTest = process.env.WEB_SIDELOAD_TEST !== undefined; yield launchApp(app, yield generateSideloadUrl(manifestFileName, manifest, document, isTest)); }); } function launchApp(app, sideloadFile) { return tslib_1.__awaiter(this, void 0, void 0, function* () { console.log(`Launching ${app} via ${sideloadFile}`); if (sideloadFile) { if (app === office_addin_manifest_1.OfficeApp.Outlook) { // put the Outlook.exe path in quotes if it contains spaces if (sideloadFile.indexOf(" ") >= 0) { sideloadFile = `"${sideloadFile}"`; } (0, process_1.startDetachedProcess)(sideloadFile); } else { yield open(sideloadFile, { wait: false }); } } }); } //# sourceMappingURL=sideload.js.map