office-addin-dev-settings
Version:
Configure developer settings for Office Add-ins.
366 lines • 17.5 kB
JavaScript
// 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
;