Commit da36b791 authored by Hugo NOUTS's avatar Hugo NOUTS
Browse files

feature(consent): Deleting GRDF konnector also removes user's consent

parent c8b322f8
{
"version": "1.0.3",
"version": "1.0.4",
"name": "GRDF",
"type": "konnector",
"language": "node",
......@@ -60,5 +60,6 @@
}
}
},
"manifest_version": "2"
}
"manifest_version": "2",
"on_delete_account": "onDeleteAccount.js"
}
\ No newline at end of file
{
"name": "grdf",
"version": "1.0.3",
"version": "1.0.4",
"description": "",
"repository": {
"type": "git",
......@@ -28,6 +28,7 @@
"start": "node ./src/index.js",
"dev": "cozy-konnector-dev",
"standalone": "cozy-konnector-standalone",
"onDeleteAccount": "cozy-konnector-dev src/onDeleteAccount.js",
"pretest": "npm run clean",
"clean": "rm -rf ./data",
"build": "webpack",
......@@ -39,6 +40,7 @@
},
"dependencies": {
"axios": "^0.20.0",
"cozy-client": "23.22.0",
"cozy-konnector-libs": "4.34.5",
"husky": "4.3.0",
"jsonwebtoken": "^8.5.1",
......
const { log } = require('cozy-konnector-libs')
const CozyClient = require('cozy-client').default
const { Q } = require('cozy-client')
const {
APP_NAME,
DOCTYPE_ACCOUNTS,
DOCTYPE_ACCOUNTS_VERSION
} = require('./constants')
function getAccessToken(environment) {
try {
if (environment === 'development') {
const cozyCredentials = JSON.parse(process.env.COZY_CREDENTIALS)
return cozyCredentials.token.accessToken
} else {
return process.env.COZY_CREDENTIALS.trim()
}
} catch (err) {
log(
'error',
`Please provide proper COZY_CREDENTIALS environment variable. ${process.env.COZY_CREDENTIALS} is not OK`
)
throw err
}
}
function getCozyUrl() {
if (process.env.COZY_URL === undefined) {
log('error', 'Please provide COZY_URL environment variable.')
throw new Error('COZY_URL environment variable is absent/not valid')
} else {
return process.env.COZY_URL
}
}
function getSchema() {
return {
accounts: {
doctype: DOCTYPE_ACCOUNTS,
doctypeVersion: DOCTYPE_ACCOUNTS_VERSION
}
}
}
function initCozyClient(accountId) {
const environment =
process.env.NODE_ENV === 'none' ? 'production' : process.env.NODE_ENV
try {
const uri = getCozyUrl(environment)
const token = getAccessToken(environment)
const appMetadata = {
slug: APP_NAME,
sourceAccount: accountId,
version: '1.0.3'
}
const schema = getSchema()
return new CozyClient({ uri, token, appMetadata, schema })
} catch (err) {
log('error', 'Unable to initialize cozy client')
throw err
}
}
class CozyUtils {
constructor(accountId) {
this.client = initCozyClient(accountId)
}
/*
Update io.cozy.accounts auth.accountName field
*/
async getAccountInfos(accountId) {
try {
log('debug', 'SENDING FIND HARVEST ECOLYO REQUEST ACCOUNT : ' + accountId)
const query = Q(DOCTYPE_ACCOUNTS)
// eslint-disable-next-line @typescript-eslint/camelcase
.where({ account_type: 'grdfgrandlyon' })
.limitBy(1)
const { data: accounts } = await this.client.query(query)
return accounts[0] ? accounts[0] : null
} catch (err) {
log(
'warn',
`Error while trying to fetch account info (for ${accountId}): ${err.message}`
)
}
}
save(params) {
return this.client.save(params)
}
}
module.exports = CozyUtils
const APP_NAME = `konnector-grdfgrandlyon`
const DOCTYPE_ACCOUNTS = 'io.cozy.accounts'
const DOCTYPE_ACCOUNTS_VERSION = 1
const DOCTYPE_CONTACTS = 'io.cozy.contacts'
const DOCTYPE_CONTACTS_ACCOUNT = 'io.cozy.contacts.accounts'
const DOCTYPE_CONTACTS_VERSION = 2
const DOCTYPE_CONTACTS_ACCOUNT_VERSION = 1
const SHOULD_SYNC_ORPHAN_DEFAULT_VALUE = true
module.exports = {
APP_NAME,
DOCTYPE_ACCOUNTS,
DOCTYPE_ACCOUNTS_VERSION,
DOCTYPE_CONTACTS,
DOCTYPE_CONTACTS_ACCOUNT,
DOCTYPE_CONTACTS_VERSION,
DOCTYPE_CONTACTS_ACCOUNT_VERSION,
SHOULD_SYNC_ORPHAN_DEFAULT_VALUE
}
function getAccountRev() {
try {
return process.env.NODE_ENV === 'development' ||
process.env.NODE_ENV === 'test'
? 'fakeAccountRev'
: JSON.parse(process.env.COZY_FIELDS).account_rev
} catch (err) {
throw new Error(`You must provide 'account' in COZY_FIELDS: ${err.message}`)
}
}
module.exports = getAccountRev
function getAccountSecret() {
try {
return process.env.NODE_ENV === 'development' ||
process.env.NODE_ENV === 'test'
? 'fakeAccountSecret'
: JSON.parse(process.env.COZY_PARAMETERS).secret
} catch (err) {
throw new Error(
`You must provide 'account-types' in COZY_PARAMETERS: ${err.message}`
)
}
}
module.exports = getAccountSecret
......@@ -57,7 +57,6 @@ async function start(fields) {
fields.access_token
) {
id_pce = this._account.oauth_callback_results.pce
log('debug', 'THE ID_PCE SENDING TO GETDATA : ' + id_pce)
const grdfData = await getData(fields.access_token, id_pce)
if (grdfData) {
......@@ -91,7 +90,6 @@ async function start(fields) {
// Retrieve data from grdf API
async function getData(token, idPCE) {
log('debug', 'ENTERING GETDATA')
var myHeaders = new Headers()
myHeaders.append('Content-Type', 'application/x-ndjson')
myHeaders.append('Authorization', 'Bearer ' + token)
......@@ -108,13 +106,12 @@ async function getData(token, idPCE) {
startDate +
'&date_fin=' +
endDate
log('debug', 'GET DATA URL ' + url)
const rep = await fetch(url, requestOptions)
.then(async response => {
if (response.status !== 200) {
throw new Error(response.status + ' - ' + response.statusText)
}
return await response.text()
return response.text()
})
.then(result => {
return result.match(/.+/g).map(s => {
......@@ -186,7 +183,7 @@ async function storeData(data, doctype, filterKeys) {
const filteredDocuments = await hydrateAndFilter(data, doctype, {
keys: filterKeys
})
return await addData(filteredDocuments, doctype)
return addData(filteredDocuments, doctype)
}
/**
......
const { cozyClient, log } = require("cozy-konnector-libs");
const getAccountId = require("./helpers/getAccountId");
const getAccountRev = require("./helpers/getAccountRev");
const getAccountSecret = require("./helpers/getAccountSecret");
const moment = require("moment");
require("moment-timezone");
moment.locale("fr"); // set the language
moment.tz.setDefault("Europe/Paris"); // set the timezone
async function onDeleteAccount(accountId) {
const accountRev = getAccountRev();
if (accountRev) {
try {
let body = "";
let access_token = "";
body = await cozyClient.fetchJSON(
"GET",
`/data/io.cozy.accounts/${accountId}?rev=${accountRev}`
);
if (body.oauth.access_token) {
access_token = body.oauth.access_token;
} else {
throw new Error(
"cozyClient.fetchJson account_rev has encountered an error"
);
}
if (moment().diff(body.oauth.expires_at) > 0) {
// token is expired, need a new one. grdf does not provide a refresh token
// so we request a new one from a client_credentials query
// first we fetch credentials secrets from account-type
const accountSecret = getAccountSecret();
if (accountSecret) {
var myTokenHeaders = new Headers();
myTokenHeaders.append(
"Content-Type",
"application/x-www-form-urlencoded"
);
var urlencoded = new URLSearchParams();
urlencoded.append("grant_type", "client_credentials");
urlencoded.append("client_id", accountSecret.client_id);
urlencoded.append("client_secret", accountSecret.client_secret);
urlencoded.append("scope", "/adict/v1");
var requestOptionsToken = {
method: "POST",
headers: myTokenHeaders,
body: urlencoded,
redirect: "follow"
};
access_token = await fetch(
"https://sofit-sso-oidc.grdf.fr/openam/oauth2/realms/externeGrdf/access_token",
requestOptionsToken
)
.then(async response => {
if (response.status !== 200) {
throw new Error(response.status + " - " + response.statusText);
}
return response.text();
})
.then(result => {
return result.match(/.+/g).map(s => {
result = JSON.parse(s);
if (result.access_token) {
return result.access_token;
}
});
})
.catch(error => {
log("debug", "Error from get access_token [onDeleteAccount]");
throw error;
});
} else {
throw new Error(
"Access Token is expired and konnector failed to get a new one"
);
}
}
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Accept", "application/x-ndjson");
myHeaders.append("Authorization", "Bearer " + access_token);
var raw = JSON.stringify({
role_tiers: ["AUTORISE_CONTRAT_FOURNITURE"],
etat_droit_acces: ["Active"],
id_pce: [body.oauth_callback_results.pce]
});
var requestOptions = {
method: "POST",
headers: myHeaders,
body: raw,
redirect: "follow"
};
let accessRights = await fetch(
"https://api.grdf.fr/adict/v1/droits_acces",
requestOptions
)
.then(async response => {
if (response.status !== 200) {
throw new Error(response.status + " - " + response.statusText);
}
return response.text();
})
.then(result => {
return result.match(/.+/g).map(s => {
result = JSON.parse(s);
if (result.id_droit_acces !== null) {
return result.id_droit_acces;
}
});
})
.catch(error => {
log("debug", "Error from get droits_access");
throw error;
});
// remove unwanted commas
accessRights = accessRights.toString().replace(/,\s*$/, "");
if (accessRights) {
var myDeleteHeaders = new Headers();
myDeleteHeaders.append("Cache-Control", "no-cache");
myDeleteHeaders.append("Content-Type", "application/json");
myDeleteHeaders.append("Authorization", "Bearer " + access_token);
var deleteRaw = JSON.stringify({});
var deleteRequestOptions = {
method: "PATCH",
headers: myDeleteHeaders,
body: deleteRaw,
redirect: "follow"
};
var url = "https://api.grdf.fr/adict/v1/droit_acces/" + accessRights;
await fetch(url, deleteRequestOptions)
.then(async response => {
if (response.status !== 200) {
throw new Error(response.status + " - " + response.statusText);
}
return response.text();
})
.catch(error => {
log("debug", "Error from delete droits_access");
throw error;
});
log("debug", "Active consent was successfully removed");
} else {
log("debug", "No active consent");
throw new Error("No active access right was found for given user");
}
} catch (err) {
log(
"warn",
`Error while trying to remove grdf consent (for ${accountRev}): ${err.message}`
);
}
} else {
throw new Error(
"No account revision was found, something went wrong during the deletion of said account"
);
}
}
const accountId = getAccountId();
onDeleteAccount(accountId).then(
() => {
log(
"info",
`onDeleteAccount: Successfully retrieved grdf account from account doctype.`
);
},
err => {
log(
"error",
`onDeleteAccount: An error occured during getGrdfAccountInfos script: ${err.message}`
);
}
);
module.exports = { onDeleteAccount };
......@@ -4,7 +4,7 @@ const webpack = require('webpack')
const fs = require('fs')
const SvgoInstance = require('svgo')
const entry = require('./package.json').main
const index = require('./package.json').main
const readManifest = () =>
JSON.parse(fs.readFileSync(path.join(__dirname, './manifest.konnector')))
......@@ -28,12 +28,15 @@ try {
const appIconRX = iconName && new RegExp(`[^/]*/${iconName}`)
module.exports = {
entry,
entry: {
index,
onDeleteAccount: './src/onDeleteAccount.js'
},
target: 'node',
mode: 'none',
output: {
path: path.join(__dirname, 'build'),
filename: 'index.js'
filename: '[name].js'
},
plugins: [
new CopyPlugin({
......
......@@ -74,6 +74,13 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.9.2":
version "7.17.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.0.tgz#b8d142fc0f7664fb3d9b5833fd40dcbab89276c0"
integrity sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/template@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278"
......@@ -107,6 +114,24 @@
lodash "^4.17.19"
to-fast-properties "^2.0.0"
"@cozy/minilog@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@cozy/minilog/-/minilog-1.0.0.tgz#1acc1aad849261e931e255a5f181b638315f7b84"
integrity sha512-IkDHF9CLh0kQeSEVsou59ar/VehvenpbEUjLfwhckJyOUqZnKAWmXy8qrBgMT5Loxr8Xjs2wmMnj0D67wP00eQ==
dependencies:
microee "0.0.6"
"@jest/types@^26.6.2":
version "26.6.2"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e"
integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==
dependencies:
"@types/istanbul-lib-coverage" "^2.0.0"
"@types/istanbul-reports" "^3.0.0"
"@types/node" "*"
"@types/yargs" "^15.0.0"
chalk "^4.0.0"
"@nodelib/fs.scandir@2.1.3":
version "2.1.3"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b"
......@@ -228,11 +253,43 @@
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd"
integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44"
integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==
"@types/istanbul-lib-report@*":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686"
integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==
dependencies:
"@types/istanbul-lib-coverage" "*"
"@types/istanbul-reports@^3.0.0":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff"
integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==
dependencies:
"@types/istanbul-lib-report" "*"
"@types/jest@^26.0.20":
version "26.0.24"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a"
integrity sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==
dependencies:
jest-diff "^26.0.0"
pretty-format "^26.0.0"
"@types/json-schema@^7.0.5":
version "7.0.6"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==
"@types/lodash@^4.14.170":
version "4.14.178"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.178.tgz#341f6d2247db528d4a13ddbb374bcdc80406f4f8"
integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==
"@types/node@*":
version "14.11.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.11.1.tgz#56af902ad157e763f9ba63d671c39cda3193c835"
......@@ -248,6 +305,18 @@
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24"
integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==
"@types/yargs-parser@*":
version "20.2.1"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129"
integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==
"@types/yargs@^15.0.0":
version "15.0.14"
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06"
integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==
dependencies:
"@types/yargs-parser" "*"
"@webassemblyjs/ast@1.9.0":
version "1.9.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964"
......@@ -1445,6 +1514,32 @@ cozy-client@13.15.0:
sift "^6.0.0"
url-search-params-polyfill "^7.0.0"
cozy-client@23.22.0:
version "23.22.0"
resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-23.22.0.tgz#2cc3c256635dcbbaef160bf37df7480a1938967c"
integrity sha512-zoKvEA83/4c0JU+T3ZoeLYoKnJsbz7V9nVJ89cAW0KJ8HESztZhumAjNJwo7lTJYh/lZkEhHF5QugP5NJTV0lg==
dependencies:
"@cozy/minilog" "1.0.0"
"@types/jest" "^26.0.20"
"@types/lodash" "^4.14.170"
btoa "^1.2.1"
cozy-device-helper "^1.12.0"
cozy-flags "2.7.1"
cozy-logger "^1.6.0"
cozy-stack-client "^23.19.0"
json-stable-stringify "^1.0.1"
lodash "^4.17.13"
microee "^0.0.6"
node-fetch "^2.6.1"
open "^7.0.2"
prop-types "^15.6.2"
react-redux "^7.2.0"
redux "3 || 4"
redux-thunk "^2.3.0"
server-destroy "^1.0.1"
sift "^6.0.0"
url-search-params-polyfill "^7.0.0"
cozy-client@^13.13.0:
version "13.21.0"
resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-13.21.0.tgz#931e3056c933d0760567c734641e3c830381328d"
......@@ -1467,6 +1562,13 @@ cozy-client@^13.13.0:
sift "^6.0.0"
url-search-params-polyfill "^7.0.0"
cozy-device-helper@^1.12.0:
version "1.17.0"
resolved "https://registry.yarnpkg.com/cozy-device-helper/-/cozy-device-helper-1.17.0.tgz#fbce9737ea83c67969b2b173163b37299a36283c"
integrity sha512-G61i75dPe/JwLUxN0foWG34lnm+0iybMu05AjoXv/UU2fRsTPfNnsHH4ZRi5JS6OPK4ccuj+ffRmabdywo23TA==
dependencies:
lodash "^4.17.19"
cozy-device-helper@^1.7.3:
version "1.10.2"
resolved "https://registry.yarnpkg.com/cozy-device-helper/-/cozy-device-helper-1.10.2.tgz#f744ce65c76d1e5a95e30bf6c08bcc6d9d772f37"
......@@ -1486,6 +1588,13 @@ cozy-doctypes@^1.73.0:
lodash "4.17.19"
prop-types "^15.7.2"
cozy-flags@2.7.1:
version "2.7.1"
resolved "https://registry.yarnpkg.com/cozy-flags/-/cozy-flags-2.7.1.tgz#f37251fee248ef9bef079a22bc52954f1a892dfc"
integrity sha512-TtVhuyMSRADRr4q5LSaRjq6u03S5m1zkZRc8n3q8bfad86FizqGC02m3e/Zh4kWTwnsO0pVW+mzeVSsBqDVT/g==
dependencies:
microee "^0.0.6"
cozy-jobs-cli@1.13.6:
version "1.13.6"
resolved "https://registry.yarnpkg.com/cozy-jobs-cli/-/cozy-jobs-cli-1.13.6.tgz#04f0e28d260da51ee02fccce1da6f9353a446f46"
......@@ -1550,6 +1659,16 @@ cozy-stack-client@^13.12.1, cozy-stack-client@^13.20.2:
mime "^2.4.0"
qs "^6.7.0"
cozy-stack-client@^23.19.0:
version "23.19.0"
resolved "https://registry.yarnpkg.com/cozy-stack-client/-/cozy-stack-client-23.19.0.tgz#2972c3dcc151b13c0f65749f341a6349170fe1d3"
integrity sha512-oq7/ERKy/Gg3jnxSi0rs3upvBccsGmmfdMiIa9hhJcw/Vxl7NMmjUM2itPnfmBNAMfBax6VlB8HWI1LY87fLuw==
dependencies:
cozy-flags "2.7.1"
detect-node "^2.0.4"
mime "^2.4.0"
qs "^6.7.0"
create-ecdh@^4.0.0:
version "4.0.4"
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e"
......@@ -1805,6 +1924,11 @@ detect-node@^2.0.4:
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
diff-sequences@^26.6.2:
version "26.6.2"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1"
integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==
diffie-hellman@^5.0.0:
version "5.0.3"
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
......@@ -3366,6 +3490,21 @@ isstream@0.1.x, isstream@~0.1.2:
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=