Compare commits
2 Commits
refacto_ss
...
florent-we
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5299c101c2 | ||
|
|
83ca34807d |
@@ -9,8 +9,8 @@ export default class Logs {
|
||||
{
|
||||
filter: [process.env.DEBUG, filter],
|
||||
level,
|
||||
transport,
|
||||
},
|
||||
transport
|
||||
}
|
||||
])
|
||||
})
|
||||
}
|
||||
|
||||
@@ -123,6 +123,7 @@
|
||||
"uuid": "^8.3.1",
|
||||
"value-matcher": "^0.2.0",
|
||||
"vhd-lib": "^1.2.0",
|
||||
"web-push": "^3.4.5",
|
||||
"ws": "^7.1.2",
|
||||
"xdg-basedir": "^4.0.0",
|
||||
"xen-api": "^0.34.3",
|
||||
|
||||
@@ -20,6 +20,7 @@ import proxyConsole from './proxy-console.mjs'
|
||||
import pw from 'pw'
|
||||
import serveStatic from 'serve-static'
|
||||
import stoppable from 'stoppable'
|
||||
import webpush from 'web-push'
|
||||
import WebServer from 'http-server-plus'
|
||||
import WebSocket from 'ws'
|
||||
import xdg from 'xdg-basedir'
|
||||
@@ -71,8 +72,8 @@ configure([
|
||||
{
|
||||
filter: process.env.DEBUG,
|
||||
level: 'info',
|
||||
transport: transportConsole(),
|
||||
},
|
||||
transport: transportConsole()
|
||||
}
|
||||
])
|
||||
|
||||
const log = createLogger('xo:main')
|
||||
@@ -84,7 +85,7 @@ const DEPRECATED_ENTRIES = ['users', 'servers']
|
||||
async function loadConfiguration() {
|
||||
const config = await appConf.load(APP_NAME, {
|
||||
appDir: APP_DIR,
|
||||
ignoreUnknownFormats: true,
|
||||
ignoreUnknownFormats: true
|
||||
})
|
||||
|
||||
log.info('Configuration loaded.')
|
||||
@@ -105,7 +106,7 @@ async function updateLocalConfig(diff) {
|
||||
const localConfig = await fse.readFile(LOCAL_CONFIG_FILE).then(JSON.parse, () => ({}))
|
||||
merge(localConfig, diff)
|
||||
await fse.outputFile(LOCAL_CONFIG_FILE, JSON.stringify(localConfig), {
|
||||
mode: 0o600,
|
||||
mode: 0o600
|
||||
})
|
||||
}
|
||||
|
||||
@@ -135,8 +136,8 @@ async function createExpressApp(config) {
|
||||
saveUninitialized: false,
|
||||
secret: sessionSecret,
|
||||
store: new MemoryStore({
|
||||
checkPeriod: 24 * 3600 * 1e3,
|
||||
}),
|
||||
checkPeriod: 24 * 3600 * 1e3
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
@@ -174,7 +175,7 @@ async function setUpPassport(express, xo, { authentication: authCfg, http: { coo
|
||||
res.send(
|
||||
signInPage({
|
||||
error: req.flash('error')[0],
|
||||
strategies,
|
||||
strategies
|
||||
})
|
||||
)
|
||||
})
|
||||
@@ -193,7 +194,7 @@ async function setUpPassport(express, xo, { authentication: authCfg, http: { coo
|
||||
signInPage({
|
||||
error: req.flash('error')[0],
|
||||
otp: true,
|
||||
strategies,
|
||||
strategies
|
||||
})
|
||||
)
|
||||
})
|
||||
@@ -219,7 +220,7 @@ async function setUpPassport(express, xo, { authentication: authCfg, http: { coo
|
||||
const { user, isPersistent } = req.session
|
||||
const token = await xo.createAuthenticationToken({
|
||||
expiresIn: isPersistent ? PERMANENT_VALIDITY : SESSION_VALIDITY,
|
||||
userId: user.id,
|
||||
userId: user.id
|
||||
})
|
||||
|
||||
res.cookie('token', token.id, {
|
||||
@@ -227,7 +228,7 @@ async function setUpPassport(express, xo, { authentication: authCfg, http: { coo
|
||||
|
||||
// a session (non-permanent) cookie must not have an expiration date
|
||||
// because it must not survive browser restart
|
||||
...(isPersistent ? { expires: new Date(token.expiration) } : undefined),
|
||||
...(isPersistent ? { expires: new Date(token.expiration) } : undefined)
|
||||
})
|
||||
|
||||
delete req.session.isPersistent
|
||||
@@ -286,6 +287,30 @@ async function setUpPassport(express, xo, { authentication: authCfg, http: { coo
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
// ==============================================================
|
||||
const publicVapidKey = 'BDAqBcWLLjbzGSMjVqlhZmU88uiAVascwXn5mbiuMVFpsXiJixtIxVpu06pIX1b8cjXKYawsv-FuGhp9oH_1dwc'
|
||||
const privateVapidKey = 'b1QTbeDFOeu0th23w9bDEpLHfkSKGvXJ3VQq50gHEcQ'
|
||||
webpush.setVapidDetails('mailto:example@yourdomain.org', publicVapidKey, privateVapidKey)
|
||||
|
||||
// subscribe route
|
||||
express.use(createExpress.json())
|
||||
express.post('/service-worker-subscribe', (req, res) => {
|
||||
// get push subscription object from the request
|
||||
const subscription = req.body
|
||||
|
||||
// send status 201 for the request
|
||||
res.status(201).json({})
|
||||
// create paylod: specified the detals of the push notification
|
||||
const payload = JSON.stringify({
|
||||
title: 'Titre de ma notification from server',
|
||||
body: 'Contenu de ma notification',
|
||||
url: 'https://www.vates.fr'
|
||||
})
|
||||
|
||||
// pass the object into sendNotification fucntion and catch any error
|
||||
webpush.sendNotification(subscription, payload).catch(err => console.error(err))
|
||||
})
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
@@ -319,14 +344,14 @@ async function registerPlugin(pluginPath, pluginName) {
|
||||
getDataDir: () => {
|
||||
const dir = `${datadir}/${pluginName}`
|
||||
return fse.ensureDir(dir).then(() => dir)
|
||||
},
|
||||
}
|
||||
})
|
||||
: factory
|
||||
;[instance, configurationSchema, configurationPresets, testSchema] = await Promise.all([
|
||||
handleFactory(factory),
|
||||
handleFactory(configurationSchema),
|
||||
handleFactory(configurationPresets),
|
||||
handleFactory(testSchema),
|
||||
handleFactory(testSchema)
|
||||
])
|
||||
|
||||
await this.registerPlugin(
|
||||
@@ -363,11 +388,11 @@ async function registerPluginsInPath(path, prefix) {
|
||||
})
|
||||
|
||||
await Promise.all(
|
||||
files.map(name => {
|
||||
if (name.startsWith(prefix)) {
|
||||
files
|
||||
.filter(name => name.startsWith(prefix))
|
||||
.map(name => {
|
||||
return registerPluginWrapper.call(this, `${path}/${name}`, name.slice(prefix.length))
|
||||
}
|
||||
})
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@@ -376,7 +401,7 @@ async function registerPlugins(xo) {
|
||||
[new URL('../node_modules', import.meta.url).pathname, '/usr/local/lib/node_modules'].map(path =>
|
||||
Promise.all([
|
||||
registerPluginsInPath.call(xo, path, 'xo-server-'),
|
||||
registerPluginsInPath.call(xo, `${path}/@xen-orchestra`, 'server-'),
|
||||
registerPluginsInPath.call(xo, `${path}/@xen-orchestra`, 'server-')
|
||||
])
|
||||
)
|
||||
)
|
||||
@@ -418,7 +443,7 @@ async function makeWebServerListen(
|
||||
const pems = await genSelfSignedCert()
|
||||
await Promise.all([
|
||||
fse.outputFile(cert, pems.cert, { flag: 'wx', mode: 0o400 }),
|
||||
fse.outputFile(key, pems.key, { flag: 'wx', mode: 0o400 }),
|
||||
fse.outputFile(key, pems.key, { flag: 'wx', mode: 0o400 })
|
||||
])
|
||||
log.info('new certificate generated', { cert, key })
|
||||
opts.cert = pems.cert
|
||||
@@ -464,7 +489,7 @@ const setUpProxies = (express, opts, xo) => {
|
||||
.createServer({
|
||||
changeOrigin: true,
|
||||
ignorePath: true,
|
||||
xfwd: true,
|
||||
xfwd: true
|
||||
})
|
||||
.on('error', (error, req, res) => {
|
||||
// `res` can be either a `ServerResponse` or a `Socket` (which does not have
|
||||
@@ -478,7 +503,7 @@ const setUpProxies = (express, opts, xo) => {
|
||||
const { method, url } = req
|
||||
log.error('failed to proxy request', {
|
||||
error,
|
||||
req: { method, url },
|
||||
req: { method, url }
|
||||
})
|
||||
})
|
||||
|
||||
@@ -494,7 +519,7 @@ const setUpProxies = (express, opts, xo) => {
|
||||
|
||||
proxy.web(req, res, {
|
||||
agent: new URL(target).hostname === 'localhost' ? undefined : xo.httpAgent,
|
||||
target: target + url.slice(prefix.length),
|
||||
target: target + url.slice(prefix.length)
|
||||
})
|
||||
|
||||
return
|
||||
@@ -506,7 +531,7 @@ const setUpProxies = (express, opts, xo) => {
|
||||
|
||||
// WebSocket proxy.
|
||||
const webSocketServer = new WebSocket.Server({
|
||||
noServer: true,
|
||||
noServer: true
|
||||
})
|
||||
xo.hooks.on('stop', () => fromCallback.call(webSocketServer, 'close'))
|
||||
|
||||
@@ -519,7 +544,7 @@ const setUpProxies = (express, opts, xo) => {
|
||||
|
||||
proxy.ws(req, socket, head, {
|
||||
agent: new URL(target).hostname === 'localhost' ? undefined : xo.httpAgent,
|
||||
target: target + url.slice(prefix.length),
|
||||
target: target + url.slice(prefix.length)
|
||||
})
|
||||
|
||||
return
|
||||
@@ -546,7 +571,7 @@ const setUpApi = (webServer, xo, config) => {
|
||||
const webSocketServer = new WebSocket.Server({
|
||||
...config.apiWebSocketOptions,
|
||||
|
||||
noServer: true,
|
||||
noServer: true
|
||||
})
|
||||
xo.hooks.on('stop', () => fromCallback.call(webSocketServer, 'close'))
|
||||
|
||||
@@ -614,7 +639,7 @@ const CONSOLE_PROXY_PATH_RE = /^\/api\/consoles\/(.*)$/
|
||||
|
||||
const setUpConsoleProxy = (webServer, xo) => {
|
||||
const webSocketServer = new WebSocket.Server({
|
||||
noServer: true,
|
||||
noServer: true
|
||||
})
|
||||
xo.hooks.on('stop', () => fromCallback.call(webSocketServer, 'close'))
|
||||
|
||||
@@ -644,7 +669,7 @@ const setUpConsoleProxy = (webServer, xo) => {
|
||||
timestamp: Date.now(),
|
||||
userId: user.id,
|
||||
userIp: remoteAddress,
|
||||
userName: user.name,
|
||||
userName: user.name
|
||||
}
|
||||
|
||||
if (vm.is_control_domain) {
|
||||
@@ -663,7 +688,7 @@ const setUpConsoleProxy = (webServer, xo) => {
|
||||
socket.on('close', () => {
|
||||
xo.emit('xo:audit', 'consoleClosed', {
|
||||
...data,
|
||||
timestamp: Date.now(),
|
||||
timestamp: Date.now()
|
||||
})
|
||||
log.info(`- Console proxy (${user.name} - ${remoteAddress})`)
|
||||
})
|
||||
@@ -710,7 +735,7 @@ export default async function main(args) {
|
||||
blocked((time, stack) => {
|
||||
logPerf.info(`blocked for ${ms(time)}`, {
|
||||
time,
|
||||
stack,
|
||||
stack
|
||||
})
|
||||
}, options)
|
||||
}
|
||||
@@ -742,7 +767,7 @@ export default async function main(args) {
|
||||
appVersion: APP_VERSION,
|
||||
config,
|
||||
httpServer: webServer,
|
||||
safeMode,
|
||||
safeMode
|
||||
})
|
||||
|
||||
// Register web server close on XO stop.
|
||||
|
||||
@@ -25,28 +25,28 @@ const gulp = require('gulp')
|
||||
// ===================================================================
|
||||
|
||||
function lazyFn(factory) {
|
||||
let fn = function () {
|
||||
let fn = function() {
|
||||
fn = factory()
|
||||
return fn.apply(this, arguments)
|
||||
}
|
||||
|
||||
return function () {
|
||||
return function() {
|
||||
return fn.apply(this, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
const livereload = lazyFn(function () {
|
||||
const livereload = lazyFn(function() {
|
||||
const livereload = require('gulp-refresh')
|
||||
livereload.listen({
|
||||
port: LIVERELOAD_PORT,
|
||||
port: LIVERELOAD_PORT
|
||||
})
|
||||
|
||||
return livereload
|
||||
})
|
||||
|
||||
const pipe = lazyFn(function () {
|
||||
const pipe = lazyFn(function() {
|
||||
let current
|
||||
function pipeCore(streams) {
|
||||
let i, n, stream
|
||||
@@ -63,7 +63,7 @@ const pipe = lazyFn(function () {
|
||||
}
|
||||
|
||||
const push = Array.prototype.push
|
||||
return function (streams) {
|
||||
return function(streams) {
|
||||
try {
|
||||
if (!(streams instanceof Array)) {
|
||||
streams = []
|
||||
@@ -79,7 +79,7 @@ const pipe = lazyFn(function () {
|
||||
}
|
||||
})
|
||||
|
||||
const resolvePath = lazyFn(function () {
|
||||
const resolvePath = lazyFn(function() {
|
||||
return require('path').resolve
|
||||
})
|
||||
|
||||
@@ -87,7 +87,7 @@ const resolvePath = lazyFn(function () {
|
||||
|
||||
// Similar to `gulp.src()` but the pattern is relative to `SRC_DIR`
|
||||
// and files are automatically watched when not in production mode.
|
||||
const src = lazyFn(function () {
|
||||
const src = lazyFn(function() {
|
||||
function resolve(path) {
|
||||
return path ? resolvePath(SRC_DIR, path) : SRC_DIR
|
||||
}
|
||||
@@ -100,7 +100,7 @@ const src = lazyFn(function () {
|
||||
base: base,
|
||||
cwd: base,
|
||||
passthrough: opts && opts.passthrough,
|
||||
sourcemaps: opts && opts.sourcemaps,
|
||||
sourcemaps: opts && opts.sourcemaps
|
||||
})
|
||||
}
|
||||
: function src(pattern, opts) {
|
||||
@@ -111,11 +111,11 @@ const src = lazyFn(function () {
|
||||
base: base,
|
||||
cwd: base,
|
||||
passthrough: opts && opts.passthrough,
|
||||
sourcemaps: opts && opts.sourcemaps,
|
||||
sourcemaps: opts && opts.sourcemaps
|
||||
}),
|
||||
require('gulp-watch')(pattern, {
|
||||
base: base,
|
||||
cwd: base,
|
||||
cwd: base
|
||||
}),
|
||||
require('gulp-plumber')()
|
||||
)
|
||||
@@ -125,13 +125,13 @@ const src = lazyFn(function () {
|
||||
// Similar to `gulp.dest()` but the output directory is relative to
|
||||
// `DIST_DIR` and default to `./`, and files are automatically live-
|
||||
// reloaded when not in production mode.
|
||||
const dest = lazyFn(function () {
|
||||
const dest = lazyFn(function() {
|
||||
function resolve(path) {
|
||||
return path ? resolvePath(DIST_DIR, path) : DIST_DIR
|
||||
}
|
||||
|
||||
const opts = {
|
||||
sourcemaps: '.',
|
||||
sourcemaps: '.'
|
||||
}
|
||||
|
||||
return PRODUCTION
|
||||
@@ -162,7 +162,7 @@ function browserify(path, opts) {
|
||||
|
||||
// Required by Watchify.
|
||||
cache: {},
|
||||
packageCache: {},
|
||||
packageCache: {}
|
||||
})
|
||||
|
||||
const plugins = opts.plugins
|
||||
@@ -178,7 +178,7 @@ function browserify(path, opts) {
|
||||
bundler = require('watchify')(bundler, {
|
||||
// do not watch in `node_modules`
|
||||
// https://github.com/browserify/watchify#options
|
||||
ignoreWatch: true,
|
||||
ignoreWatch: true
|
||||
})
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ function browserify(path, opts) {
|
||||
path = resolvePath(SRC_DIR, path)
|
||||
|
||||
let stream = new (require('readable-stream'))({
|
||||
objectMode: true,
|
||||
objectMode: true
|
||||
})
|
||||
|
||||
let write
|
||||
@@ -204,28 +204,28 @@ function browserify(path, opts) {
|
||||
new (require('vinyl'))({
|
||||
base: SRC_DIR,
|
||||
contents: buffer,
|
||||
path: path,
|
||||
path: path
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
if (PRODUCTION) {
|
||||
write = function (data) {
|
||||
write = function(data) {
|
||||
stream.push(data)
|
||||
stream.push(null)
|
||||
}
|
||||
} else {
|
||||
stream = require('gulp-plumber')().pipe(stream)
|
||||
write = function (data) {
|
||||
write = function(data) {
|
||||
stream.push(data)
|
||||
}
|
||||
|
||||
bundler.on('update', bundle)
|
||||
}
|
||||
|
||||
stream._read = function () {
|
||||
this._read = function () {}
|
||||
stream._read = function() {
|
||||
this._read = function() {}
|
||||
bundle()
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ gulp.task(function buildPages() {
|
||||
require('gulp-pug')(),
|
||||
DEVELOPMENT &&
|
||||
require('gulp-embedlr')({
|
||||
port: LIVERELOAD_PORT,
|
||||
port: LIVERELOAD_PORT
|
||||
}),
|
||||
dest()
|
||||
)
|
||||
@@ -255,10 +255,10 @@ gulp.task(function buildScripts() {
|
||||
'modular-cssify',
|
||||
{
|
||||
css: DIST_DIR + '/modules.css',
|
||||
from: undefined,
|
||||
},
|
||||
],
|
||||
],
|
||||
from: undefined
|
||||
}
|
||||
]
|
||||
]
|
||||
}),
|
||||
require('gulp-sourcemaps').init({ loadMaps: true }),
|
||||
PRODUCTION && require('gulp-terser')(),
|
||||
@@ -275,18 +275,18 @@ gulp.task(function buildStyles() {
|
||||
dest()
|
||||
)
|
||||
})
|
||||
|
||||
gulp.task(function copyAssets() {
|
||||
return pipe(
|
||||
src(['assets/**/*', 'favicon.*']),
|
||||
src('fontawesome-webfont.*', {
|
||||
base: __dirname + '/../../node_modules/font-awesome/fonts', // eslint-disable-line no-path-concat
|
||||
passthrough: true,
|
||||
base: path.join(__dirname, '/../../node_modules/font-awesome/fonts'), // eslint-disable-line no-path-concat
|
||||
passthrough: true
|
||||
}),
|
||||
src(['!*.css', 'font-mfizz.*'], {
|
||||
base: __dirname + '/../../node_modules/font-mfizz/dist', // eslint-disable-line no-path-concat
|
||||
passthrough: true,
|
||||
passthrough: true
|
||||
}),
|
||||
src(['serviceworker.js']),
|
||||
dest()
|
||||
)
|
||||
})
|
||||
|
||||
@@ -5,6 +5,7 @@ import React, { Component } from 'react'
|
||||
import ReactNotify from 'react-notify'
|
||||
import { connectStore } from 'utils'
|
||||
import { isAdmin } from 'selectors'
|
||||
import fetch from './fetch'
|
||||
|
||||
let instance
|
||||
|
||||
@@ -12,8 +13,47 @@ export let error
|
||||
export let info
|
||||
export let success
|
||||
|
||||
const publicVapidKey = 'BDAqBcWLLjbzGSMjVqlhZmU88uiAVascwXn5mbiuMVFpsXiJixtIxVpu06pIX1b8cjXKYawsv-FuGhp9oH_1dwc'
|
||||
|
||||
function urlBase64ToUint8Array(base64String) {
|
||||
const padding = '='.repeat((4 - (base64String.length % 4)) % 4)
|
||||
const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/')
|
||||
|
||||
const rawData = window.atob(base64)
|
||||
const outputArray = new Uint8Array(rawData.length)
|
||||
|
||||
for (let i = 0; i < rawData.length; ++i) {
|
||||
outputArray[i] = rawData.charCodeAt(i)
|
||||
}
|
||||
return outputArray
|
||||
}
|
||||
|
||||
// register the service worker, register our push api, send the notification
|
||||
async function registerNotificationServiceWorker() {
|
||||
// register service worker
|
||||
const register = await navigator.serviceWorker.register('/serviceworker.js', {
|
||||
scope: '/'
|
||||
})
|
||||
|
||||
// register push
|
||||
const subscription = await register.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
|
||||
// public vapid key
|
||||
applicationServerKey: urlBase64ToUint8Array(publicVapidKey)
|
||||
})
|
||||
// Send push notification
|
||||
await fetch('/service-worker-subscribe', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(subscription),
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@connectStore({
|
||||
isAdmin,
|
||||
isAdmin
|
||||
})
|
||||
export class Notification extends Component {
|
||||
componentDidMount() {
|
||||
@@ -21,6 +61,11 @@ export class Notification extends Component {
|
||||
throw new Error('Notification is a singleton!')
|
||||
}
|
||||
instance = this
|
||||
|
||||
// check if the serveice worker can work in the current browser
|
||||
if ('serviceWorker' in navigator) {
|
||||
registerNotificationServiceWorker()
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
||||
27
packages/xo-web/src/serviceworker.js
Normal file
27
packages/xo-web/src/serviceworker.js
Normal file
@@ -0,0 +1,27 @@
|
||||
const version = 7;
|
||||
|
||||
self.addEventListener('install', () => {
|
||||
console.log(`Installation du service worker v${version}`);
|
||||
return self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener('activate', () => console.log(`Activation du service worker v${version}`));
|
||||
|
||||
self.addEventListener('push', event => {
|
||||
const dataJSON = event.data.json();
|
||||
console.log(dataJSON)
|
||||
const notificationOptions = {
|
||||
body: dataJSON.body,
|
||||
data: {
|
||||
url: dataJSON.url,
|
||||
}
|
||||
};
|
||||
|
||||
return self.registration.showNotification(dataJSON.title, notificationOptions);
|
||||
});
|
||||
|
||||
self.addEventListener('notificationclick', event => {
|
||||
const url = event.notification.data.url;
|
||||
event.notification.close();
|
||||
event.waitUntil(clients.openWindow(url));
|
||||
});
|
||||
55
yarn.lock
55
yarn.lock
@@ -2680,7 +2680,7 @@ asap@^2.0.6, asap@~2.0.3:
|
||||
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
|
||||
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
|
||||
|
||||
asn1.js@^5.0.0, asn1.js@^5.2.0:
|
||||
asn1.js@^5.0.0, asn1.js@^5.2.0, asn1.js@^5.3.0:
|
||||
version "5.4.1"
|
||||
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07"
|
||||
integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==
|
||||
@@ -3474,6 +3474,11 @@ buffer-crc32@^0.2.13, buffer-crc32@~0.2.3:
|
||||
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
|
||||
|
||||
buffer-equal-constant-time@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
|
||||
integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=
|
||||
|
||||
buffer-equal@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe"
|
||||
@@ -5808,6 +5813,13 @@ ecc-jsbn@~0.1.1:
|
||||
jsbn "~0.1.0"
|
||||
safer-buffer "^2.1.0"
|
||||
|
||||
ecdsa-sig-formatter@1.0.11:
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
|
||||
integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
ee-first@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||
@@ -8310,6 +8322,13 @@ http-signature@~1.2.0:
|
||||
jsprim "^1.2.2"
|
||||
sshpk "^1.7.0"
|
||||
|
||||
http_ece@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/http_ece/-/http_ece-1.1.0.tgz#74780c6eb32d8ddfe9e36a83abcd81fe0cd4fb75"
|
||||
integrity sha512-bptAfCDdPJxOs5zYSe7Y3lpr772s1G346R4Td5LgRUeCwIGpCGDUTJxRrhTNcAXbx37spge0kWEIH7QAYWNTlA==
|
||||
dependencies:
|
||||
urlsafe-base64 "~1.0.0"
|
||||
|
||||
https-browserify@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||
@@ -9900,6 +9919,23 @@ just-reduce-object@^1.0.3:
|
||||
resolved "https://registry.yarnpkg.com/just-reduce-object/-/just-reduce-object-1.1.0.tgz#d29d172264f8511c74462de30d72d5838b6967e6"
|
||||
integrity sha512-nGyg7N9FEZsyrGQNilkyVLxKPsf96iel5v0DrozQ19ML+96HntyS/53bOP68iK/kZUGvsL3FKygV8nQYYhgTFw==
|
||||
|
||||
jwa@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.0.tgz#a7e9c3f29dae94027ebcaf49975c9345593410fc"
|
||||
integrity sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==
|
||||
dependencies:
|
||||
buffer-equal-constant-time "1.0.1"
|
||||
ecdsa-sig-formatter "1.0.11"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
jws@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4"
|
||||
integrity sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==
|
||||
dependencies:
|
||||
jwa "^2.0.0"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
keycode@^2.1.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.0.tgz#3d0af56dc7b8b8e5cba8d0a97f107204eec22b04"
|
||||
@@ -16513,6 +16549,11 @@ url@^0.11.0, url@~0.11.0:
|
||||
punycode "1.3.2"
|
||||
querystring "0.2.0"
|
||||
|
||||
urlsafe-base64@^1.0.0, urlsafe-base64@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/urlsafe-base64/-/urlsafe-base64-1.0.0.tgz#23f89069a6c62f46cf3a1d3b00169cefb90be0c6"
|
||||
integrity sha1-I/iQaabGL0bPOh07ABac77kL4MY=
|
||||
|
||||
use@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
|
||||
@@ -16938,6 +16979,18 @@ wcwidth@^1.0.1:
|
||||
dependencies:
|
||||
defaults "^1.0.3"
|
||||
|
||||
web-push@^3.4.5:
|
||||
version "3.4.5"
|
||||
resolved "https://registry.yarnpkg.com/web-push/-/web-push-3.4.5.tgz#f94074ff150538872c7183e4d8881c8305920cf1"
|
||||
integrity sha512-2njbTqZ6Q7ZqqK14YpK1GGmaZs3NmuGYF5b7abCXulUIWFSlSYcZ3NBJQRFcMiQDceD7vQknb8FUuvI1F7Qe/g==
|
||||
dependencies:
|
||||
asn1.js "^5.3.0"
|
||||
http_ece "1.1.0"
|
||||
https-proxy-agent "^5.0.0"
|
||||
jws "^4.0.0"
|
||||
minimist "^1.2.5"
|
||||
urlsafe-base64 "^1.0.0"
|
||||
|
||||
webidl-conversions@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff"
|
||||
|
||||
Reference in New Issue
Block a user