Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for InTune Single-Sign-On #1280

Merged
merged 1 commit into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ Here is the list of available arguments and its usage:
| spellCheckerLanguages | Array of languages to use with Electron's spell checker | [] |
| ssoBasicAuthUser | Login that will be sent for basic_auth SSO login. | string |
| ssoBasicAuthPasswordCommand | Command to execute, grab stdout and use it as a password for basic_auth SSO login. | string |
| ssoIntuneEnabled | Enable InTune Single-Sign-On | false
| ssoIntuneAuthUser | User (e-mail) to be used for InTune SSO login. | string |
| trayIconEnabled | Enable tray icon | true |
| url | Microsoft Teams URL | string |
| useMutationTitleLogic | Use MutationObserver to update counter from title | true |
Expand Down
10 changes: 10 additions & 0 deletions app/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,16 @@ function argv(configPath, appVersion) {
describe: 'Command to execute to retrieve password for SSO basic auth.',
type: 'string'
},
ssoInTuneEnabled: {
default: false,
describe: 'Enable Single-Sign-On using Microsoft InTune.',
type: 'boolean'
},
ssoInTuneAuthUser: {
default: '',
describe: 'User (e-mail) to use for InTune SSO.',
type: 'string'
},
trayIconEnabled: {
default: true,
describe: 'Enable tray icon',
Expand Down
91 changes: 91 additions & 0 deletions app/intune/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
const dbus = require('@homebridge/dbus-native');
const { LucidLog } = require('lucid-log');

var sessionBus = dbus.sessionBus();

var intuneAccount = null;

var brokerService = sessionBus.getService('com.microsoft.identity.broker1');

function processInTuneAccounts(logger, resp, ssoInTuneAuthUser) {
response = JSON.parse(resp);
if ('error' in response) {
logger.warn('Failed to retrieve InTune account list: ' + response.error.context);
return;
};

if (ssoInTuneAuthUser == '') {
intuneAccount = response.accounts[0];
logger.debug('Using first available InTune account (' + intuneAccount.username + ')');
} else {
for (account in response.accounts) {
if (account.username == ssoIntuneAuthUser) {
intuneAccount = account;
logger.debug('Found matching InTune account (' + intuneAccount.username + ')');
break;
}
}
if (intuneAccount == null) {
logger.warn('Failed to find matching InTune account for ' + ssoIntuneAuthUser + '.');
}
}
}

exports.initSso = function initIntuneSso(logger, ssoInTuneAuthUser) {
logger.debug("Initializing InTune SSO");
brokerService.getInterface(
'/com/microsoft/identity/broker1',
'com.microsoft.identity.Broker1', function(err, broker) {
if (err) {
logger.warn('Failed to find microsoft-identity-broker DBus interface');
return;
}
broker.getAccounts('0.0', '', JSON.stringify({'clientId': '88200948-af09-45a1-9c03-53cdcc75c183', 'redirectUri':'urn:ietf:oob'}), function(err, resp) {
IsmaelMartinez marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly you get a different response from the broker if you use a specific client id (like the one from Edge, d7b530a4-7680-4c23-a8bf-c52c121d2e87). When using that, I just get a single account back instead of three time the same.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That single account is highly likely the MS Entra identity for the synchronized work profile in MS Edge. I'm not sure how this is going to react in case you have a second work profile synchronized to a different MS Entra user identity.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I already experienced that MS Intune had issues in the past in that multiple work profiles scenario.

if (err) {
logger.warn('Failed to communicate with microsoft-identity-broker');
return;
}
processInTuneAccounts(logger, resp, ssoInTuneAuthUser);
});
});
}

exports.setupUrlFilter = function setupUrlFilter(filter) {
filter.urls.push('https://login.microsoftonline.com/*');
}

exports.isSsoUrl = function isSsoUrl(url) {
return intuneAccount != null && url.startsWith('https://login.microsoftonline.com/');
}

function processPrtResponse(logger, resp, detail) {
response = JSON.parse(resp);
if ('error' in response) {
logger.warn('Failed to retrieve Intune SSO cookie: ' + response.error.context);
} else {
logger.debug('Adding SSO credential');
detail.requestHeaders['X-Ms-Refreshtokencredential'] = response['cookieContent'];
}
}

exports.addSsoCookie = function addIntuneSsoCookie(logger, detail, callback) {
logger.debug('Retrieving InTune SSO cookie');
if (intuneAccount == null) {
logger.info("InTune SSO not active");
callback({
requestHeaders: detail.requestHeaders
});
return;
}
brokerService.getInterface(
'/com/microsoft/identity/broker1',
'com.microsoft.identity.Broker1', function(err, broker) {
broker.acquirePrtSsoCookie('0.0', '', JSON.stringify({'ssoUrl':detail.url, 'account':intuneAccount, 'authParameters':{'authority':'https://login.microsoftonline.com/common/'}}), function(err, resp) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KrissN Last week I developed a plugin for Firefox on Linux that uses exactly the same approach. This will be OSSed soon. I'm currently working on a similar thing for EWS in Evolution.

I'm just wondering if the authParameters part here is really sufficient (apparently it works), as the Edge Browser puts more data in there:

Sample request from Edge

            'accessTokenToRenew': '',
            'account': account,
            'additionalQueryParametersForAuthorization': {},
            'authority': 'https://login.microsoftonline.com/common',
            'authorizationType': 8,  # OAUTH2
            'clientId': EDGE_BROWSER_CLIENT_ID,
            'decodedClaims': '',
            'enrollmentId': '',
            'password': '',
            'popParams': None,
            'redirectUri': 'https://login.microsoftonline.com'
                           '/common/oauth2/nativeclient',
            'requestedScopes': scopes,
            'username': account['username'],
            'uxContextHandle': -1

The interesting parts here are:

  • repetition of the account
  • authorization type
  • client ID
  • requested scopes (which usually is just https://graph.microsoft.com/.default)
  • username

Did you find documentation about the exact interface, or also just reverse engineered it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here, a client ID can be passed. I recommend to use the one from edge here, as Edge itself is technically more or less a chrome (webkit). An alternative would be to make it configurable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I have found no documentation about this DBus interface. I have reverse-engineered it, in a way that I have found a minimum set of arguments that have worked.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KrissN thanks for the confirmation. It would be good if we could at least make the client id configurable. Apart from that, we should also ensure that the service is running before calling it on DBus. Otherwise, the sign-in does not work directly after boot (before another application like Edge activates it via DBus). For reference, you might want to have a look how I implemented that in the Firefox / Chrome plugin: https://github.com/siemens/linux-entra-sso/blob/main/linux-entra-sso.py#L63

processPrtResponse(logger, resp, detail);
callback({
requestHeaders: detail.requestHeaders
});
});
});
}

20 changes: 15 additions & 5 deletions app/mainAppWindow/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const TrayIconChooser = require('../browser/tools/trayIconChooser');
const { AppConfiguration } = require('../appConfiguration');
const connMgr = require('../connectionManager');
const fs = require('fs');
const intune = require('../intune');

/**
* @type {TrayIconChooser}
Expand Down Expand Up @@ -65,6 +66,10 @@ exports.onAppReady = async function onAppReady(configGroup) {
levels: config.appLogLevels.split(',')
});

if (config.ssoInTuneEnabled) {
intune.initSso(logger, config.ssoInTuneAuthUser);
}

window = await createWindow();

if (config.trayIconEnabled) {
Expand Down Expand Up @@ -323,12 +328,16 @@ function setImgSrcSecurityPolicy(policies) {
* @param {Electron.BeforeSendResponse} callback
*/
function onBeforeSendHeadersHandler(detail, callback) {
if (detail.url.startsWith(customBGServiceUrl.href)) {
detail.requestHeaders['Access-Control-Allow-Origin'] = '*';
if (intune.isSsoUrl(detail.url)) {
intune.addSsoCookie(logger, detail, callback);
} else {
if (detail.url.startsWith(customBGServiceUrl.href)) {
IsmaelMartinez marked this conversation as resolved.
Show resolved Hide resolved
detail.requestHeaders['Access-Control-Allow-Origin'] = '*';
}
callback({
IsmaelMartinez marked this conversation as resolved.
Show resolved Hide resolved
requestHeaders: detail.requestHeaders
});
}
callback({
requestHeaders: detail.requestHeaders
});
}

/**
Expand Down Expand Up @@ -409,6 +418,7 @@ function addEventHandlers() {

function getWebRequestFilterFromURL() {
const filter = customBGServiceUrl.protocol === 'http:' ? { urls: ['http://*/*'] } : { urls: ['https://*/*'] };
intune.setupUrlFilter(filter);
return filter;
}

Expand Down
7 changes: 7 additions & 0 deletions com.github.IsmaelMartinez.teams_for_linux.appdata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
<url type="bugtracker">https://github.com/IsmaelMartinez/teams-for-linux/issues</url>
<launchable type="desktop-id">com.github.IsmaelMartinez.teams_for_linux.desktop</launchable>
<releases>
<release version="1.5.3" date="2024-06-04">
<description>
<ul>
<li>Add support for Single Sign On using Microsoft Intune</li>
</ul>
</description>
</release>
<release version="1.5.2" date="2024-05-28">
<description>
<ul>
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "teams-for-linux",
"version": "1.5.2",
"version": "1.5.3",
"main": "app/index.js",
"description": "Unofficial client for Microsoft Teams for Linux",
"homepage": "https://github.com/IsmaelMartinez/teams-for-linux",
Expand Down Expand Up @@ -40,6 +40,7 @@
"release": "electron-builder"
},
"dependencies": {
"@homebridge/dbus-native": "0.6.0",
"@electron/remote": "^2.1.2",
"electron-is-dev": "2.0.0",
"electron-store": "8.2.0",
Expand Down
106 changes: 106 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,29 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.0.0.tgz#1a9e4b4c96d8c7886e0110ed310a0135144a1691"
integrity sha512-RThY/MnKrhubF6+s1JflwUjPEsnCEmYCWwqa/aRISKWNXGZ9epUwft4bUMM35SdKF9xvBrLydAM1RDHd1Z//ZQ==

"@homebridge/[email protected]":
version "0.6.0"
resolved "https://registry.yarnpkg.com/@homebridge/dbus-native/-/dbus-native-0.6.0.tgz#25052dd03216b977298e4c9db19b7aeb1d2363f4"
integrity sha512-xObqQeYHTXmt6wsfj10+krTo4xbzR9BgUfX2aQ+edDC9nc4ojfzLScfXCh3zluAm6UCowKw+AFfXn6WLWUOPkg==
dependencies:
"@homebridge/long" "^5.2.1"
"@homebridge/put" "^0.0.8"
event-stream "^4.0.1"
hexy "^0.3.5"
minimist "^1.2.6"
safe-buffer "^5.1.2"
xml2js "^0.6.2"

"@homebridge/long@^5.2.1":
version "5.2.1"
resolved "https://registry.yarnpkg.com/@homebridge/long/-/long-5.2.1.tgz#1c7568775b78e1a0fd75a7b3fa7a995f0388ab37"
integrity sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA==

"@homebridge/put@^0.0.8":
version "0.0.8"
resolved "https://registry.yarnpkg.com/@homebridge/put/-/put-0.0.8.tgz#4b8b99f2c4d58bc762718863699df2c5bc0b4b8a"
integrity sha512-mwxLHHqKebOmOSU0tsPEWQSBHGApPhuaqtNpCe7U+AMdsduweANiu64E9SXXUtdpyTjsOpgSMLhD1+kbLHD2gA==

"@humanwhocodes/config-array@^0.12.3":
version "0.12.3"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.12.3.tgz#a6216d90f81a30bedd1d4b5d799b47241f318072"
Expand Down Expand Up @@ -795,6 +818,11 @@ dotenv@^9.0.2:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-9.0.2.tgz#dacc20160935a37dea6364aa1bef819fb9b6ab05"
integrity sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==

duplexer@^0.1.1, duplexer@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==

eastasianwidth@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
Expand Down Expand Up @@ -1012,6 +1040,19 @@ esutils@^2.0.2:
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==

event-stream@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-4.0.1.tgz#4092808ec995d0dd75ea4580c1df6a74db2cde65"
integrity sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==
dependencies:
duplexer "^0.1.1"
from "^0.1.7"
map-stream "0.0.7"
pause-stream "^0.0.11"
split "^1.0.1"
stream-combiner "^0.2.2"
through "^2.3.8"

extract-zip@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
Expand Down Expand Up @@ -1116,6 +1157,11 @@ form-data@^4.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"

from@^0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe"
integrity sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==

fs-extra@^10.0.0, fs-extra@^10.1.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
Expand Down Expand Up @@ -1302,6 +1348,11 @@ hasown@^2.0.0:
dependencies:
function-bind "^1.1.2"

hexy@^0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/hexy/-/hexy-0.3.5.tgz#adcd5ee47d66aca3581d771743a509a5176e45f9"
integrity sha512-UCP7TIZPXz5kxYJnNOym+9xaenxCLor/JyhKieo8y8/bJWunGh9xbhy3YrgYJUQ87WwfXGm05X330DszOfINZw==

hosted-git-info@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224"
Expand Down Expand Up @@ -1585,6 +1636,11 @@ lucid-log@^0.0.3:
dependencies:
chalk "^4.1.2"

[email protected]:
version "0.0.7"
resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8"
integrity sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==

matcher@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca"
Expand Down Expand Up @@ -1821,6 +1877,13 @@ path-scurry@^1.10.2:
lru-cache "^10.2.0"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"

pause-stream@^0.0.11:
version "0.0.11"
resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
integrity sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==
dependencies:
through "~2.3"

pend@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
Expand Down Expand Up @@ -1951,6 +2014,11 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"

safe-buffer@^5.1.2:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==

"safer-buffer@>= 2.1.2 < 3.0.0":
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
Expand All @@ -1963,6 +2031,11 @@ sanitize-filename@^1.6.3:
dependencies:
truncate-utf8-bytes "^1.0.0"

sax@>=0.6.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f"
integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==

sax@^1.2.4:
version "1.3.0"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0"
Expand Down Expand Up @@ -2043,6 +2116,13 @@ source-map@^0.6.0:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==

split@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9"
integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==
dependencies:
through "2"

sprintf-js@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a"
Expand All @@ -2053,6 +2133,14 @@ stat-mode@^1.0.0:
resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-1.0.0.tgz#68b55cb61ea639ff57136f36b216a291800d1465"
integrity sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==

stream-combiner@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.2.2.tgz#aec8cbac177b56b6f4fa479ced8c1912cee52858"
integrity sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==
dependencies:
duplexer "~0.1.1"
through "~2.3.4"

"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
Expand Down Expand Up @@ -2129,6 +2217,11 @@ text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==

through@2, through@^2.3.8, through@~2.3, through@~2.3.4:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==

tmp-promise@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/tmp-promise/-/tmp-promise-3.0.3.tgz#60a1a1cc98c988674fcbfd23b6e3367bdeac4ce7"
Expand Down Expand Up @@ -2241,11 +2334,24 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==

xml2js@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499"
integrity sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==
dependencies:
sax ">=0.6.0"
xmlbuilder "~11.0.0"

xmlbuilder@>=11.0.1, xmlbuilder@^15.1.1:
version "15.1.1"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5"
integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==

xmlbuilder@~11.0.0:
version "11.0.1"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==

y18n@^5.0.5:
version "5.0.8"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
Expand Down