From bd69be71378e1c494e953fda7d34eb41163e4dba Mon Sep 17 00:00:00 2001 From: garrettmills Date: Sun, 24 Oct 2021 13:12:58 -0500 Subject: [PATCH] Implement RADIUS server! --- Units.flitter.js | 1 + app/assets/app/dash/SideBar.component.js | 6 + app/assets/app/resource/App.resource.js | 10 + .../app/resource/radius/Client.resource.js | 71 +++++ app/controllers/api/v1/App.controller.js | 44 +++ app/controllers/api/v1/Radius.controller.js | 190 +++++++++++ app/models/Application.model.js | 2 + app/models/radius/Client.model.js | 32 ++ app/routing/routers/api/v1/radius.routes.js | 48 +++ app/unit/RadiusUnit.js | 156 ++++++++++ config/auth.config.js | 3 +- config/radius.config.js | 10 + index.js | 2 + locale/en_US/api.locale.js | 1 + package.json | 2 + yarn.lock | 294 +++++++++++++++++- 16 files changed, 861 insertions(+), 11 deletions(-) create mode 100644 app/assets/app/resource/radius/Client.resource.js create mode 100644 app/controllers/api/v1/Radius.controller.js create mode 100644 app/models/radius/Client.model.js create mode 100644 app/routing/routers/api/v1/radius.routes.js create mode 100644 app/unit/RadiusUnit.js create mode 100644 config/radius.config.js diff --git a/Units.flitter.js b/Units.flitter.js index 1e1a8e7..249a905 100644 --- a/Units.flitter.js +++ b/Units.flitter.js @@ -44,6 +44,7 @@ const FlitterUnits = { 'LDAPController': require('./app/unit/LDAPControllerUnit'), 'LDAPRoutingUnit': require('./app/unit/LDAPRoutingUnit'), 'OpenIDConnect' : require('./app/unit/OpenIDConnectUnit'), + 'Radius' : require('./app/unit/RadiusUnit'), /* * The Core Flitter Units diff --git a/app/assets/app/dash/SideBar.component.js b/app/assets/app/dash/SideBar.component.js index 3af2c13..c2e7f57 100644 --- a/app/assets/app/dash/SideBar.component.js +++ b/app/assets/app/dash/SideBar.component.js @@ -90,6 +90,12 @@ export default class SideBarComponent extends Component { type: 'resource', resource: 'oauth/Client', }, + { + text: 'RADIUS Clients', + action: 'list', + type: 'resource', + resource: 'radius/Client', + }, { text: 'OpenID Connect Clients', action: 'list', diff --git a/app/assets/app/resource/App.resource.js b/app/assets/app/resource/App.resource.js index 6a8a61f..a512750 100644 --- a/app/assets/app/resource/App.resource.js +++ b/app/assets/app/resource/App.resource.js @@ -112,6 +112,16 @@ class AppResource extends CRUDBase { value: 'id', }, }, + { + name: 'Associated RADIUS Clients', + field: 'radius_client_ids', + type: 'select.dynamic.multiple', + options: { + resource: 'radius/Client', + display: 'name', + value: 'id', + }, + }, { name: 'Associated OpenID Connect Clients', field: 'openid_client_ids', diff --git a/app/assets/app/resource/radius/Client.resource.js b/app/assets/app/resource/radius/Client.resource.js new file mode 100644 index 0000000..69e8ddd --- /dev/null +++ b/app/assets/app/resource/radius/Client.resource.js @@ -0,0 +1,71 @@ +import CRUDBase from '../CRUDBase.js' +import { session } from '../../service/Session.service.js'; + +class ClientResource extends CRUDBase { + constructor() { + super() + + this.endpoint = '/api/v1/radius/clients' + this.required_fields = ['name'] + this.permission_base = 'v1:radius:clients' + + this.item = 'RADIUS Client' + this.plural = 'RADIUS Clients' + + this.listing_definition = { + display: ``, + columns: [ + { + name: 'Client Name', + field: 'name', + }, + ], + actions: [ + { + type: 'resource', + position: 'main', + action: 'insert', + text: 'Create New', + color: 'success', + }, + { + type: 'resource', + position: 'row', + action: 'update', + icon: 'fa fa-edit', + color: 'primary', + }, + { + type: 'resource', + position: 'row', + action: 'delete', + icon: 'fa fa-times', + color: 'danger', + confirm: true, + }, + ], + } + + this.form_definition = { + fields: [ + { + name: 'Client Name', + field: 'name', + placeholder: 'Awesome External App', + required: true, + type: 'text', + }, + { + name: 'Client Secret', + field: 'secret', + type: 'text', + readonly: true, + hidden: ['insert'], + }, + ], + } + } +} + +const radius_client = new ClientResource() +export { radius_client } diff --git a/app/controllers/api/v1/App.controller.js b/app/controllers/api/v1/App.controller.js index 0fa88ae..09275e2 100644 --- a/app/controllers/api/v1/App.controller.js +++ b/app/controllers/api/v1/App.controller.js @@ -115,6 +115,28 @@ class AppController extends Controller { application.oauth_client_ids = oauth_client_ids } + // Verify RADIUS client IDs + const RadiusClient = this.models.get('radius:Client') + if ( req.body.radius_client_ids ) { + const parsed = typeof req.body.radius_client_ids === 'string' ? this.utility.infer(req.body.radius_client_ids) : req.body.radius_client_ids + const radius_client_ids = Array.isArray(parsed) ? parsed : [parsed] + for ( const id of radius_client_ids ) { + const client = await RadiusClient.findById(id) + if ( !client || !client.active || !req.user.can(`radius:client:${client.id}:view`) ) + return res.status(400) + .message(`${req.T('api.invalid_radius_client_id')} ${id}`) + .api() + + const other_assoc_app = await Application.findOne({ radius_client_ids: client.id }) + if ( other_assoc_app ) + return res.status(400) // TODO translate this + .message(`The RADIUS client ${client.name} is already associated with an existing application (${other_assoc_app.name}).`) + .api() + } + + application.radius_client_ids = radius_client_ids + } + // Verify OpenID client IDs const OpenIDClient = this.models.get('openid:Client') if ( req.body.openid_client_ids ) { @@ -242,6 +264,28 @@ class AppController extends Controller { application.oauth_client_ids = oauth_client_ids } else application.oauth_client_ids = [] + // Verify OAuth client IDs + const RadiusClient = this.models.get('radius:Client') + if ( req.body.radius_client_ids ) { + const parsed = typeof req.body.radius_client_ids === 'string' ? this.utility.infer(req.body.radius_client_ids) : req.body.radius_client_ids + const radius_client_ids = Array.isArray(parsed) ? parsed : [parsed] + for ( const id of radius_client_ids ) { + const client = await RadiusClient.findById(id) + if ( !client || !client.active || !req.user.can(`radius:client:${client.id}:view`) ) + return res.status(400) + .message(`${req.T('api.invalid_radius_client_id')} ${id}`) + .api() + + const other_assoc_app = await Application.findOne({ radius_client_ids: client.id }) + if ( other_assoc_app && other_assoc_app.id !== application.id ) + return res.status(400) // TODO translate this + .message(`The RADIUS client ${client.name} is already associated with an existing application (${other_assoc_app.name}).`) + .api() + } + + application.radius_client_ids = radius_client_ids + } else application.radius_client_ids = [] + // Verify OpenID client IDs const OpenIDClient = this.models.get('openid:Client') if ( req.body.openid_client_ids ) { diff --git a/app/controllers/api/v1/Radius.controller.js b/app/controllers/api/v1/Radius.controller.js new file mode 100644 index 0000000..8f58388 --- /dev/null +++ b/app/controllers/api/v1/Radius.controller.js @@ -0,0 +1,190 @@ +const { Controller } = require('libflitter') + +class RadiusController extends Controller { + static get services() { + return [...super.services, 'models', 'output'] + } + + async attempt(req, res, next) { + const User = this.models.get('auth:User') + const Client = this.models.get('radius:Client') + + if ( !req.body.username || !req.body.password ) { + this.output.error('RADIUS error: missing username or password') + return this.fail(res) + } + + const parts = String(req.body.username).split('@') + parts.reverse() + + const clientId = parts.shift() + parts.reverse() + + const username = parts.join('@') + const password = req.body.password + + const user = await User.findOne({ uid: username, active: true }) + if ( !user ) { + this.output.error(`RADIUS error: invalid username: ${username}`) + return this.fail(res) + } + + const client = await Client.findById(clientId) + if ( !client || !client.active ) { + this.output.error(`RADIUS error: invalid client: ${clientId}`) + return this.fail(res) + } + + // Check if the credentials are an app_password + const app_password_verified = Array.isArray(user.app_passwords) + && user.app_passwords.length > 0 + && await user.check_app_password(password) + + // Check if the user has MFA enabled. + // If so, split the incoming password to fetch the MFA code + // e.g. normalPassword:123456 + if ( !app_password_verified && user.mfa_enabled ) { + const parts = password.split(':') + const mfa_code = parts.pop() + const actual_password = parts.join(':') + + // Check the credentials + if ( !(await user.check_password(actual_password)) ) { + this.output.debug(`RADIUS error: user w/ MFA provided invalid credentials`) + return this.fail(res) + } + + // Now, check the MFA code + if ( !user.mfa_token.verify(mfa_code) ) { + this.output.debug(`RADIUS error: user w/ MFA provided invalid MFA token`) + return this.fail(res) + } + + // If not MFA, just check the credentials + } else if (!app_password_verified && !await user.check_password(password)) { + this.output.debug(`RADIUS error: user w/ simple auth provided invalid credentials`) + return this.fail(res) + } + + // Check if the user has any login interrupt traps set + if ( user.trap ) { + this.output.error(`RADIUS error: user has trap: ${user.trap}`) + return this.fail(res) + } + + // Apply the appropriate IAM policy if this SAML SP is associated with an App + // If the SAML service provider has no associated application, just allow it + const associated_app = await client.application() + if ( associated_app ) { + const Policy = this.models.get('iam:Policy') + const can_access = await Policy.check_user_access(user, associated_app.id) + if ( !can_access ) { + this.output.error(`RADIUS error: user denied IAM access`) + return this.fail(res) + } + } + + this.output.info(`Authenticated RADIUS user: ${user.uid} to IAM ${associated_app.name}`) + return res.api({ success: true }) + } + + fail(res) { + return res.status(401).api({ success: false }) + } + + async get_clients(req, res, next) { + const Client = this.models.get('radius:Client') + const clients = await Client.find({ active: true }) + const data = [] + + for ( const client of clients ) { + if ( req.user.can(`radius:client:${client.id}:view`) ) { + data.push(await client.to_api()) + } + } + + return res.api(data) + } + + async get_client(req, res, next) { + const Client = this.models.get('radius:Client') + const client = await Client.findById(req.params.id) + + if ( !client || !client.active ) + return res.status(404) + .message(req.T('api.client_not_found')) + .api() + + if ( !req.user.can(`radius:client:${client.id}:view`) ) + return res.status(401) + .message(req.T('api.insufficient_permissions')) + .api() + + return res.api(await client.to_api()) + } + + async create_client(req, res, next) { + if ( !req.user.can('radius:client:create') ) + return res.status(401) + .message(req.T('api.insufficient_permissions')) + .api() + + if ( !req.body.name ) + return res.status(400) + .message(`${req.T('api.missing_field')} name`) + .api() + + const Client = this.models.get('radius:Client') + const client = new Client({ + name: req.body.name, + }) + + await client.save() + return res.api(await client.to_api()) + } + + async update_client(req, res, next) { + const Client = this.models.get('radius:Client') + const client = await Client.findById(req.params.id) + + if ( !client || !client.active ) + return res.status(404) + .message(req.T('api.client_not_found')) + .api() + + if ( !req.user.can(`radius:client:${client.id}:update`) ) + return res.status(401) + .message(req.T('api.insufficient_permissions')) + .api() + + if ( !req.body.name ) + return res.status(400) + .message(`${req.T('api.missing_field')} name`) + .api() + + client.name = req.body.name + await client.save() + return res.api() + } + + async delete_client(req, res, next) { + const Client = this.models.get('radius:Client') + const client = await Client.findById(req.params.id) + + if ( !client || !client.active ) + return res.status(404) + .message(req.T('api.client_not_found')) + .api() + + if ( !req.user.can(`radius:client:${client.id}:delete`) ) + return res.status(401) + .message(req.T('api.insufficient_permissions')) + .api() + + client.active = false + await client.save() + return res.api() + } +} + +module.exports = exports = RadiusController diff --git a/app/models/Application.model.js b/app/models/Application.model.js index d91b53d..d7dfc55 100644 --- a/app/models/Application.model.js +++ b/app/models/Application.model.js @@ -11,6 +11,7 @@ class ApplicationModel extends Model { ldap_client_ids: [String], oauth_client_ids: [String], openid_client_ids: [String], + radius_client_ids: [String], } } @@ -24,6 +25,7 @@ class ApplicationModel extends Model { ldap_client_ids: this.ldap_client_ids, oauth_client_ids: this.oauth_client_ids, openid_client_ids: this.openid_client_ids, + radius_client_ids: this.radius_client_ids || [], } } } diff --git a/app/models/radius/Client.model.js b/app/models/radius/Client.model.js new file mode 100644 index 0000000..a7bb228 --- /dev/null +++ b/app/models/radius/Client.model.js @@ -0,0 +1,32 @@ +const { Model } = require('flitter-orm') +const {v4: uuid} = require("uuid"); + +class Client extends Model { + static get services() { + return [...super.services, 'models'] + } + + static get schema() { + return { + name: String, + secret: {type: String, default: uuid}, + active: {type: Boolean, default: true}, + } + } + + async application() { + const Application = this.models.get('Application') + return Application.findOne({ active: true, radius_client_ids: this.id }) + } + + async to_api() { + return { + id: this.id, + name: this.name, + secret: this.secret, + active: this.active, + } + } +} + +module.exports = exports = Client diff --git a/app/routing/routers/api/v1/radius.routes.js b/app/routing/routers/api/v1/radius.routes.js new file mode 100644 index 0000000..47d67a9 --- /dev/null +++ b/app/routing/routers/api/v1/radius.routes.js @@ -0,0 +1,48 @@ +const saml_routes = { + prefix: '/api/v1/radius', + + middleware: [], + + get: { + '/clients': [ + ['middleware::auth:APIRoute'], + ['middleware::api:Permission', { check: 'v1:radius:clients:list' }], + 'controller::api:v1:Radius.get_clients', + ], + '/clients/:id': [ + ['middleware::auth:APIRoute'], + ['middleware::api:Permission', { check: 'v1:radius:clients:get' }], + 'controller::api:v1:Radius.get_client', + ], + }, + + post: { + '/attempt': [ + ['middleware::auth:GuestOnly'], + 'controller::api:v1:Radius.attempt', + ], + '/clients': [ + ['middleware::auth:APIRoute'], + ['middleware::api:Permission', { check: 'v1:radius:clients:create' }], + 'controller::api:v1:Radius.create_client', + ], + }, + + patch: { + '/clients/:id': [ + ['middleware::auth:APIRoute'], + ['middleware::api:Permission', { check: 'v1:radius:clients:update' }], + 'controller::api:v1:Radius.update_client', + ], + }, + + delete: { + '/clients/:id': [ + ['middleware::auth:APIRoute'], + ['middleware::api:Permission', { check: 'v1:radius:clients:delete' }], + 'controller::api:v1:Radius.delete_client', + ], + }, +} + +module.exports = exports = saml_routes diff --git a/app/unit/RadiusUnit.js b/app/unit/RadiusUnit.js new file mode 100644 index 0000000..7226a87 --- /dev/null +++ b/app/unit/RadiusUnit.js @@ -0,0 +1,156 @@ +const { Unit } = require('libflitter') +const fs = require('fs') +const radius = require('radius') +const uuid = require('uuid').v4 + +/** + * Unit that provides a CoreID IAM-integrated RADIUS server. + */ +class RadiusUnit extends Unit { + static get services() { + return [...super.services, 'configs', 'output', 'models'] + } + + async go(app) { + const config = this.getConfig() + + // Overwrite radius-server's global config object with the user-provided values + const radiusConfig = require('radius-server/config') + for ( const key in config ) { + if ( !Object.hasOwnProperty.apply(config, [key]) ) continue + radiusConfig[key] = config[key] + } + + const { Authentication } = require('radius-server/dist/auth') + const { UDPServer } = require('radius-server/dist/server/UDPServer') + const { RadiusService } = require('radius-server/dist/radius/RadiusService') + + this.output.info('Starting RADIUS server...') + + // Create the authenticator instance + const AuthMechanismus = require(`radius-server/dist/auth/${config.authentication}`)[config.authentication] + const auth = new AuthMechanismus(config.authenticationOptions) + + const authentication = new Authentication(auth) + this.server = new UDPServer(config.port) + this.radiusService = new RadiusService(config.secret, authentication) + + // Define the server handler + this.server.on('message', async (msg, rinfo) => { + this.output.debug('Incoming RADIUS message...') + const response = await this.handleMessage(msg) + + if ( response ) { + this.output.debug('Sending response...') + this.server.sendToClient( + response.data, + rinfo.port, + rinfo.address, + (err, _bytes) => { + if ( err ) { + this.output.error(`Error sending response to:`) + this.output.error(rinfo) + } + }, + response.expectAcknowledgment + ) + } + }) + + // Start the radius server + await this.server.start() + this.output.success('Started RADIUS server!') + } + + async cleanup(app) { + if ( this.server ) { + // radius-server doesn't expose a "close" method explicitly, which is annoying + // instead, reach in and close the internal UDP socket + this.server.server.close() + } + } + + /** + * Handle an incoming radius request message. + * @param msg + * @returns {Promise<{expectAcknowledgment: boolean, data: *}|undefined>} + */ + async handleMessage(msg) { + const RadiusClient = this.models.get('radius:Client') + const clients = await RadiusClient.find({ active: true }) + + // Try the secrets for all active clients. + // If we can successfully decode the packet with a client's secret, then we know + // that the message came from that client. + let authenticatedClient + let packet + for ( const client of clients ) { + try { + packet = radius.decode({ packet: msg, secret: client.secret }) + authenticatedClient = client + break + } catch (e) {} + } + + if (packet.code !== 'Access-Request') { + console.error('unknown packet type: ', packet.code) + return + } + + // Include the RADIUS Client ID in the username so we can parse it out in the controller + // This allows us to check IAM access in the controller + packet.attributes['User-Name'] = `${packet.attributes['User-Name']}@${authenticatedClient.id}` + this.output.info(`RADIUS auth attempt: ${packet.attributes['User-Name']}`) + + const response = await this.radiusService.packetHandler.handlePacket(packet) + + // still no response, we are done here + if (!response || !response.code) { + return + } + + // all fine, return radius encoded response + return { + data: radius.encode_response({ + packet, + code: response.code, + secret: authenticatedClient.secret, // use the client's secret to encode the response + attributes: response.attributes, + }), + + // if message is accept or reject, we conside this as final message + // this means we do not expect a reponse from the client again (acknowledgement for package) + expectAcknowledgment: response.code === 'Access-Challenge', + }; + } + + getConfig() { + const baseUrl = this.configs.get('app.url') + + const config = { + port: this.configs.get('radius.port', 1812), + secret: uuid(), // this is never used - client-specific secrets are injected instead + certificate: { + cert: fs.readFileSync(this.configs.get('radius.cert_file.public')), + key: [ + { + pem: fs.readFileSync(this.configs.get('radius.cert_file.private')), + }, + ], + }, + authentication: 'HTTPAuth', + authenticationOptions: { + url: `${baseUrl}api/v1/radius/attempt`, + }, + } + + const passphrase = this.configs.get('saml.cert_file.passphrase') + if ( passphrase ) { + config.certificate.key[0].passphrase = passphrase + } + + return config + } +} + +module.exports = exports = RadiusUnit diff --git a/config/auth.config.js b/config/auth.config.js index a349e3e..ca40486 100644 --- a/config/auth.config.js +++ b/config/auth.config.js @@ -207,6 +207,7 @@ const auth_config = { ldap_client: ['ldap:bind', 'ldap:search'], coreid_base: ['my:profile'], saml_admin: ['v1:saml', 'saml'], + radius_admin: ['v1:radius', 'radius'], base_user: [ // Message Service @@ -226,7 +227,7 @@ const auth_config = { 'ldap:search:users:me', ], - root: ['v1', 'ldap', 'saml', 'profile', 'oauth', 'app', 'auth', 'iam'], + root: ['v1', 'ldap', 'saml', 'profile', 'oauth', 'app', 'auth', 'iam', 'radius'], }, diff --git a/config/radius.config.js b/config/radius.config.js new file mode 100644 index 0000000..1db17c7 --- /dev/null +++ b/config/radius.config.js @@ -0,0 +1,10 @@ +const radius_config = { + port: env('RADIUS_PORT', 1812), + + cert_file: { + public: env('RADIUS_CERT_FILE'), + private: env('RADIUS_KEY_FILE'), + }, +} + +module.exports = exports = radius_config diff --git a/index.js b/index.js index f037cc2..05a2ce7 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,5 @@ +Error.stackTraceLimit = 200 + /* * Load the units file. * ------------------------------------------------------------- diff --git a/locale/en_US/api.locale.js b/locale/en_US/api.locale.js index 50b659f..ea9de2b 100644 --- a/locale/en_US/api.locale.js +++ b/locale/en_US/api.locale.js @@ -31,6 +31,7 @@ module.exports = exports = { invalid_ldap_client_id: 'Invalid ldap_client_id:', invalid_oauth_client_id: 'Invalid oauth_client_id:', + invalid_radius_client_id: 'Invalid radius_client_id:', invalid_saml_service_provider_id: 'Invalid saml_service_provider_id:', invalid_target_type: 'Invalid target_type.', diff --git a/package.json b/package.json index 0c17087..f1d02a7 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,8 @@ "nodemailer": "^6.4.6", "oidc-provider": "^6.29.0", "qrcode": "^1.4.4", + "radius": "^1.1.4", + "radius-server": "^1.2.0", "samlp": "^3.4.1", "speakeasy": "^2.0.0", "uuid": "^8.3.0", diff --git a/yarn.lock b/yarn.lock index 22e5a5f..5aefe68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -182,6 +182,11 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@hokify/node-ts-cache@^5.4.1": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@hokify/node-ts-cache/-/node-ts-cache-5.6.0.tgz#47a7b9f2be426c03f1c1d92adcecfda06e3fa60c" + integrity sha512-VdjeFjLAT9gGrRlzjZsMeY9ZWJyfz8y8ODeZsUdSnDdwxqb0keZNAtS3PMswBzSECBfNV1RT+NGiC8j6P1Cv6w== + "@istanbuljs/load-nyc-config@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz#10602de5570baea82f8afbfa2630b24e7a8cfe5b" @@ -384,6 +389,13 @@ "@types/koa-compose" "*" "@types/node" "*" +"@types/ldapjs@^1.0.9": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@types/ldapjs/-/ldapjs-1.0.11.tgz#34077176af2b06186bd54e4a38ceb6e852387fa4" + integrity sha512-O4D1frY6xy2mQr5WouNPeltMe5EHdmU4FxbLDC6TMDX5HXOuafusGu+7Y9WAoqBaYHZ5hcFa7jfkpggyexfeXQ== + dependencies: + "@types/node" "*" + "@types/mime@*": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a" @@ -417,6 +429,11 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abstract-logging@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839" + integrity sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA== + accepts@^1.3.5, accepts@^1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -632,7 +649,7 @@ asn1@0.2.3: resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" integrity sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y= -asn1@~0.2.3: +asn1@^0.2.4, asn1@~0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== @@ -721,6 +738,13 @@ axios@^0.19.2: dependencies: follow-redirects "1.5.10" +axios@^0.21.1: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + babel-core@^5.4.7: version "5.8.38" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" @@ -929,6 +953,11 @@ bcrypt@^3.0.4: nan "2.13.2" node-pre-gyp "0.12.0" +bcryptjs@^2.4.0: + version "2.4.3" + resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" + integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms= + binary-extensions@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" @@ -1251,6 +1280,15 @@ cliui@^6.0.0: strip-ansi "^6.0.0" wrap-ansi "^6.2.0" +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + clone-response@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" @@ -1258,16 +1296,16 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +clone@2.x, clone@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + clone@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= -clone@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= - cluster-key-slot@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" @@ -1525,6 +1563,13 @@ debug@^4.1.0, debug@^4.1.1: dependencies: ms "^2.1.1" +debug@^4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + decamelize@^1.0.0, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -1831,6 +1876,11 @@ es6-promisify@^6.0.1: resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.1.tgz#6edaa45f3bd570ffe08febce66f7116be4b1cdb6" integrity sha512-J3ZkwbEnnO+fGAKrjVpeUAnZshAdfZvbhQpqfIH9kSAspReRC4nJnu8ewm55b4y9ElyeuhCTzJD0XiH8Tsbhlw== +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + escape-html@^1.0.3, escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -2212,6 +2262,11 @@ follow-redirects@1.5.10: dependencies: debug "=3.1.0" +follow-redirects@^1.14.0: + version "1.14.4" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379" + integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g== + foreground-child@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" @@ -2306,7 +2361,7 @@ gensync@^1.0.0-beta.1: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== -get-caller-file@^2.0.1: +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -2599,7 +2654,7 @@ iconv-lite@0.4.23: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@0.4.24, iconv-lite@^0.4.4, iconv-lite@^0.4.5: +iconv-lite@0.4.24, iconv-lite@^0.4.4, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -2623,6 +2678,26 @@ image-size@~0.5.0: resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= +imap-simple@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/imap-simple/-/imap-simple-5.1.0.tgz#7d8936eb1c4774f21cc38c358888fbf82c2fb57a" + integrity sha512-FLZm1v38C5ekN46l/9X5gBRNMQNVc5TSLYQ3Hsq3xBLvKwt1i5fcuShyth8MYMPuvId1R46oaPNrH92hFGHr/g== + dependencies: + iconv-lite "~0.4.13" + imap "^0.8.18" + nodeify "^1.0.0" + quoted-printable "^1.0.0" + utf8 "^2.1.1" + uuencode "0.0.4" + +imap@^0.8.18: + version "0.8.19" + resolved "https://registry.yarnpkg.com/imap/-/imap-0.8.19.tgz#3678873934ab09cea6ba48741f284da2af59d8d5" + integrity sha1-NniHOTSrCc6mukh0HyhNoq9Z2NU= + dependencies: + readable-stream "1.1.x" + utf7 ">=1.0.2" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -2646,7 +2721,7 @@ inherits@2, inherits@2.0.3, inherits@~2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -inherits@2.0.4: +inherits@2.0.4, inherits@~2.0.1: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2813,6 +2888,11 @@ is-promise@^2.0.0: resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= +is-promise@~1, is-promise@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-1.0.1.tgz#31573761c057e33c2e91aab9e96da08cefbe76e5" + integrity sha1-MVc3YcBX4zwukaq56W2gjO++duU= + is-regex@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" @@ -3179,6 +3259,13 @@ ldap-filter@0.2.2: dependencies: assert-plus "0.1.5" +ldap-filter@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/ldap-filter/-/ldap-filter-0.3.3.tgz#2b14c68a2a9d4104dbdbc910a1ca85fd189e9797" + integrity sha1-KxTGiiqdQQTb28kQocqF/Riel5c= + dependencies: + assert-plus "^1.0.0" + ldap@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/ldap/-/ldap-0.7.1.tgz#320165cd1065079607d83bfbf4308cb45ce791b9" @@ -3196,6 +3283,16 @@ ldap@^0.7.1: optionalDependencies: dtrace-provider "0.4.0" +ldapauth-fork@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ldapauth-fork/-/ldapauth-fork-5.0.1.tgz#18779a9c30371c5bbea02e3b6aaadb60819ad29c" + integrity sha512-EdELQz8zgPruqV2y88PAuAiZCgTaMjex/kEA2PIcOlPYFt75C9QFt5HGZKVQo8Sf/3Mwnr1AtiThHKcq+pRtEg== + dependencies: + "@types/ldapjs" "^1.0.9" + bcryptjs "^2.4.0" + ldapjs "^2.2.1" + lru-cache "^6.0.0" + ldapjs@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/ldapjs/-/ldapjs-1.0.2.tgz#544ff7032b7b83c68f0701328d9297aa694340f9" @@ -3213,6 +3310,20 @@ ldapjs@^1.0.2: optionalDependencies: dtrace-provider "~0.8" +ldapjs@^2.2.1, ldapjs@^2.2.3: + version "2.3.1" + resolved "https://registry.yarnpkg.com/ldapjs/-/ldapjs-2.3.1.tgz#04136815fb1f21d692ac87fab5961a04d86e8b04" + integrity sha512-kf0tHHLrpwKaBAQOhYHXgdeh2PkFuCCxWgLb1MRn67ZQVo787D2pij3mmHVZx193GIdM8xcfi8HF6AIYYnj0fQ== + dependencies: + abstract-logging "^2.0.0" + asn1 "^0.2.4" + assert-plus "^1.0.0" + backoff "^2.5.0" + ldap-filter "^0.3.3" + once "^1.4.0" + vasync "^2.2.0" + verror "^1.8.1" + less@>=2.0.0: version "3.11.1" resolved "https://registry.yarnpkg.com/less/-/less-3.11.1.tgz#c6bf08e39e02404fe6b307a3dfffafdc55bd36e2" @@ -3259,6 +3370,11 @@ libflitter@^0.59.0: status-codes "^0.0.1" uuid "^3.3.2" +line-buffer@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/line-buffer/-/line-buffer-0.1.4.tgz#e07de183310b60122fde4b335cf6606543ffb1d3" + integrity sha1-4H3hgzELYBIv3kszXPZgZUP/sdM= + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -3653,6 +3769,11 @@ ms@2.1.1, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + mv@~2: version "2.1.1" resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2" @@ -3682,6 +3803,11 @@ nanoid@^3.1.10: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.12.tgz#6f7736c62e8d39421601e4a0c77623a97ea69654" integrity sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A== +native-duplexpair@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/native-duplexpair/-/native-duplexpair-1.0.0.tgz#7899078e64bf3c8a3d732601b3d40ff05db58fa0" + integrity sha1-eJkHjmS/PIo9cyYBs9QP8F21j6A= + ncp@^2.0.0, ncp@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" @@ -3742,6 +3868,13 @@ nise@^4.0.1: just-extend "^4.0.2" path-to-regexp "^1.7.0" +node-cache@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-5.1.2.tgz#f264dc2ccad0a780e76253a694e9fd0ed19c398d" + integrity sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg== + dependencies: + clone "2.x" + node-environment-flags@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088" @@ -3793,6 +3926,14 @@ node-preload@^0.2.1: dependencies: process-on-spawn "^1.0.0" +nodeify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/nodeify/-/nodeify-1.0.1.tgz#64ab69a7bdbaf03ce107b4f0335c87c0b9e91b1d" + integrity sha1-ZKtpp7268DzhB7TwM1yHwLnpGx0= + dependencies: + is-promise "~1.0.0" + promise "~1.3.0" + nodemailer@^6.4.6: version "6.4.6" resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.4.6.tgz#d37f504f6560b36616f646a606894fe18819107f" @@ -4227,6 +4368,23 @@ promise@^7.0.1, promise@^7.1.1: dependencies: asap "~2.0.3" +promise@~1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/promise/-/promise-1.3.0.tgz#e5cc9a4c8278e4664ffedc01c7da84842b040175" + integrity sha1-5cyaTIJ45GZP/twBx9qEhCsEAXU= + dependencies: + is-promise "~1" + +promised-timeout@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/promised-timeout/-/promised-timeout-0.5.1.tgz#56bd98eb8c59e594dae85551bc54451cd4584c23" + integrity sha1-Vr2Y64xZ5ZTa6FVRvFRFHNRYTCM= + +promised-timeout@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/promised-timeout/-/promised-timeout-0.2.0.tgz#45eafcf5ed9457e2e60efa77c2c860d6ef1d816e" + integrity sha1-Rer89e2UV+LmDvp3wshg1u8dgW4= + proto-list@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" @@ -4411,6 +4569,35 @@ querystring@^0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= +quoted-printable@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/quoted-printable/-/quoted-printable-1.0.1.tgz#9eebf5eb3d11eef022b264fd2d2b6b2bb3b84cc3" + integrity sha1-nuv16z0R7vAismT9LStrK7O4TMM= + dependencies: + utf8 "^2.1.0" + +radius-server@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/radius-server/-/radius-server-1.2.0.tgz#74d5932b66906c0b5ea7763bb11bb1c6a6a219e6" + integrity sha512-JRscm5uafissZMgJYFOemiUjnwpmIWEjVAL0O/tn9Fiy2mqPAX+xVKqWEopu2BZ7NZzHScqlQnVomLyzyHk08Q== + dependencies: + "@hokify/node-ts-cache" "^5.4.1" + axios "^0.21.1" + debug "^4.3.1" + imap-simple "^5.0.0" + ldapauth-fork "^5.0.1" + ldapjs "^2.2.3" + native-duplexpair "^1.0.0" + node-cache "^5.1.2" + radius "~1.1.4" + smtp-client "^0.3.3" + yargs "~16.2.0" + +radius@^1.1.4, radius@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/radius/-/radius-1.1.4.tgz#3ce58d18a497d615618bc7d9286464ebecb50cb5" + integrity sha512-UWuzdF6xf3NpsXFZZmUEkxtEalDXj8hdmMXgbGzn7vOk6zXNsiIY2I6SJ1euHt7PTQuMoz2qDEJB+AfJDJgQYw== + random-bytes@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" @@ -4459,6 +4646,16 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +readable-stream@1.1.x: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + readable-stream@^2.0.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" @@ -4804,6 +5001,11 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + send@0.16.2: version "0.16.2" resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" @@ -4926,6 +5128,22 @@ slash@^1.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= +smtp-channel@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/smtp-channel/-/smtp-channel-0.2.3.tgz#db660868ad3b5296775ec8078c38aa634c4dcda6" + integrity sha512-5PR7qW88Z6GcLfvgop6WpUMwNoJKKQY9CP8Gpk5INbSs3UtWqMgFYkTTMaynnbj+6e4D/L0JuagbuH3fjm4+Fw== + dependencies: + line-buffer "^0.1.4" + promised-timeout "^0.2.0" + +smtp-client@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/smtp-client/-/smtp-client-0.3.3.tgz#54f5211b5613f86cb801892e298c53f60cdde515" + integrity sha512-bneg34/4sug5MAVROUaOgQFEEDQDcmv5qXa/E9mDdwjV9jOvexidMzGH9jR1cgQCsFh1yWrVToY0MCWvoVwWSA== + dependencies: + promised-timeout "0.5.1" + smtp-channel "0.2.3" + source-map-support@^0.2.10: version "0.2.10" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" @@ -5110,7 +5328,7 @@ string.prototype.trimstart@^1.0.0: define-properties "^1.1.3" es-abstract "^1.17.5" -string_decoder@0.10: +string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= @@ -5396,6 +5614,18 @@ user-home@^1.1.1: resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" integrity sha1-K1viOjK2Onyd640PKNSFcko98ZA= +utf7@>=1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/utf7/-/utf7-1.0.2.tgz#955f490aae653ba220b9456a0a8776c199360991" + integrity sha1-lV9JCq5lO6IguUVqCod2wZk2CZE= + dependencies: + semver "~5.3.0" + +utf8@^2.1.0, utf8@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.2.tgz#1fa0d9270e9be850d9b05027f63519bf46457d96" + integrity sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY= + util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -5411,6 +5641,11 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= +uuencode@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/uuencode/-/uuencode-0.0.4.tgz#c8d50370885663879385ab37e333c7e8e3b0218c" + integrity sha1-yNUDcIhWY4eThas34zPH6OOwIYw= + uuid@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" @@ -5460,6 +5695,13 @@ vasync@^1.6.4: dependencies: verror "1.6.0" +vasync@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/vasync/-/vasync-2.2.0.tgz#cfde751860a15822db3b132bc59b116a4adaf01b" + integrity sha1-z951GGChWCLbOxMrxZsRakra8Bs= + dependencies: + verror "1.10.0" + verror@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.1.0.tgz#2a4b4eb14a207051e75a6f94ee51315bf173a1b0" @@ -5560,6 +5802,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -5643,6 +5894,11 @@ y18n@^4.0.0: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" @@ -5674,6 +5930,11 @@ yargs-parser@^18.1.1: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + yargs-unparser@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" @@ -5716,6 +5977,19 @@ yargs@^15.0.2: y18n "^4.0.0" yargs-parser "^18.1.1" +yargs@~16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"