feat(planning): grille hebdomadaire complète avec API et filtres
- Connexion API via proxy Angular (résolution CORS, base path /api) - Import CSS ng-zorro global pour les modales et composants - Filtres Camion/Show câblés sur l'affichage de la grille - Camions affichés via TrucksService (linkés au show du même créneau) - Panneau de détails : spectacles + camions du jour sélectionné - Modale de création de spectacle stylisée avec fond et centrage - Positionnement précis des events à la minute dans leur créneau - Auto-scroll vers l'heure courante au chargement - Ligne "maintenant" sur la colonne du jour actuel - Régénération des services OpenAPI (nouveaux noms de types) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+63
-33
@@ -5,21 +5,14 @@ const { Minipass } = require('minipass')
|
||||
|
||||
const SPEC_ALGORITHMS = ['sha512', 'sha384', 'sha256']
|
||||
const DEFAULT_ALGORITHMS = ['sha512']
|
||||
const NODE_HASHES = crypto.getHashes()
|
||||
|
||||
// TODO: this should really be a hardcoded list of algorithms we support, rather than [a-z0-9].
|
||||
// TODO: this should really be a hardcoded list of algorithms we support,
|
||||
// rather than [a-z0-9].
|
||||
const BASE64_REGEX = /^[a-z0-9+/]+(?:=?=?)$/i
|
||||
const SRI_REGEX = /^([a-z0-9]+)-([^?]+)(\?[?\S*]*)?$/
|
||||
const SRI_REGEX = /^([a-z0-9]+)-([^?]+)([?\S*]*)$/
|
||||
const STRICT_SRI_REGEX = /^([a-z0-9]+)-([A-Za-z0-9+/=]{44,88})(\?[\x21-\x7E]*)?$/
|
||||
const VCHAR_REGEX = /^[\x21-\x7E]+$/
|
||||
|
||||
// This is a Best Effort™ at a reasonable priority for hash algos
|
||||
const DEFAULT_PRIORITY = [
|
||||
'md5', 'whirlpool', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
|
||||
// TODO - it's unclear _which_ of these Node will actually use as its name for the algorithm, so we guesswork it based on the OpenSSL names.
|
||||
'sha3', 'sha3-256', 'sha3-384', 'sha3-512', 'sha3_256', 'sha3_384', 'sha3_512',
|
||||
].filter(algo => NODE_HASHES.includes(algo))
|
||||
|
||||
const getOptString = options => options?.length ? `?${options.join('?')}` : ''
|
||||
|
||||
class IntegrityStream extends Minipass {
|
||||
@@ -106,6 +99,7 @@ class IntegrityStream extends Minipass {
|
||||
// Integrity verification mode
|
||||
const match = this.goodSri && newSri.match(this.sri, this.opts)
|
||||
if (typeof this.expectedSize === 'number' && this.size !== this.expectedSize) {
|
||||
/* eslint-disable-next-line max-len */
|
||||
const err = new Error(`stream size mismatch when checking ${this.sri}.\n Wanted: ${this.expectedSize}\n Found: ${this.size}`)
|
||||
err.code = 'EBADSIZE'
|
||||
err.found = this.size
|
||||
@@ -113,6 +107,7 @@ class IntegrityStream extends Minipass {
|
||||
err.sri = this.sri
|
||||
this.emit('error', err)
|
||||
} else if (this.sri && !match) {
|
||||
/* eslint-disable-next-line max-len */
|
||||
const err = new Error(`${this.sri} integrity checksum failed when using ${this.algorithm}: wanted ${this.digests} but got ${newSri}. (${this.size} bytes)`)
|
||||
err.code = 'EINTEGRITY'
|
||||
err.found = newSri
|
||||
@@ -142,7 +137,8 @@ class Hash {
|
||||
const strict = opts?.strict
|
||||
this.source = hash.trim()
|
||||
|
||||
// set default values so that we make V8 happy to always see a familiar object template.
|
||||
// set default values so that we make V8 happy to
|
||||
// always see a familiar object template.
|
||||
this.digest = ''
|
||||
this.algorithm = ''
|
||||
this.options = []
|
||||
@@ -160,9 +156,6 @@ class Hash {
|
||||
if (strict && !SPEC_ALGORITHMS.includes(match[1])) {
|
||||
return
|
||||
}
|
||||
if (!NODE_HASHES.includes(match[1])) {
|
||||
return
|
||||
}
|
||||
this.algorithm = match[1]
|
||||
this.digest = match[2]
|
||||
|
||||
@@ -205,12 +198,15 @@ class Hash {
|
||||
|
||||
toString (opts) {
|
||||
if (opts?.strict) {
|
||||
// Strict mode enforces the standard as close to the foot of the letter as it can.
|
||||
// Strict mode enforces the standard as close to the foot of the
|
||||
// letter as it can.
|
||||
if (!(
|
||||
// The spec has very restricted productions for algorithms.
|
||||
// https://www.w3.org/TR/CSP2/#source-list-syntax
|
||||
SPEC_ALGORITHMS.includes(this.algorithm) &&
|
||||
// Usually, if someone insists on using a "different" base64, we leave it as-is, since there are multiple standards, and the specified is not a URL-safe variant.
|
||||
// Usually, if someone insists on using a "different" base64, we
|
||||
// leave it as-is, since there's multiple standards, and the
|
||||
// specified is not a URL-safe variant.
|
||||
// https://www.w3.org/TR/CSP2/#base64_value
|
||||
this.digest.match(BASE64_REGEX) &&
|
||||
// Option syntax is strictly visual chars.
|
||||
@@ -304,7 +300,8 @@ class Integrity {
|
||||
return parse(this, { single: true }).hexDigest()
|
||||
}
|
||||
|
||||
// add additional hashes to an integrity value, but prevent *changing* an existing integrity hash.
|
||||
// add additional hashes to an integrity value, but prevent
|
||||
// *changing* an existing integrity hash.
|
||||
merge (integrity, opts) {
|
||||
const other = parse(integrity, opts)
|
||||
for (const algo in other) {
|
||||
@@ -326,25 +323,33 @@ class Integrity {
|
||||
return false
|
||||
}
|
||||
const algo = other.pickAlgorithm(opts, Object.keys(this))
|
||||
return !!algo && this[algo].find(hash =>
|
||||
other[algo].find(otherhash =>
|
||||
hash.digest === otherhash.digest
|
||||
return (
|
||||
!!algo &&
|
||||
this[algo] &&
|
||||
other[algo] &&
|
||||
this[algo].find(hash =>
|
||||
other[algo].find(otherhash =>
|
||||
hash.digest === otherhash.digest
|
||||
)
|
||||
)
|
||||
) || false
|
||||
}
|
||||
|
||||
// Pick the highest priority algorithm present, optionally also limited to a set of hashes found in another integrity.
|
||||
// When limiting it may return nothing.
|
||||
// Pick the highest priority algorithm present, optionally also limited to a
|
||||
// set of hashes found in another integrity. When limiting it may return
|
||||
// nothing.
|
||||
pickAlgorithm (opts, hashes) {
|
||||
const pickAlgorithm = opts?.pickAlgorithm || getPrioritizedHash
|
||||
let keys = Object.keys(this)
|
||||
if (hashes?.length) {
|
||||
keys = keys.filter(k => hashes.includes(k))
|
||||
}
|
||||
const keys = Object.keys(this).filter(k => {
|
||||
if (hashes?.length) {
|
||||
return hashes.includes(k)
|
||||
}
|
||||
return true
|
||||
})
|
||||
if (keys.length) {
|
||||
return keys.reduce((acc, algo) => pickAlgorithm(acc, algo) || acc)
|
||||
}
|
||||
// no intersection between this and hashes
|
||||
// no intersection between this and hashes,
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -375,7 +380,7 @@ function _parse (integrity, opts) {
|
||||
const hash = new Hash(string, opts)
|
||||
if (hash.algorithm && hash.digest) {
|
||||
const algo = hash.algorithm
|
||||
if (!Object.keys(acc).includes(algo)) {
|
||||
if (!acc[algo]) {
|
||||
acc[algo] = []
|
||||
}
|
||||
acc[algo].push(hash)
|
||||
@@ -416,7 +421,9 @@ function fromData (data, opts) {
|
||||
`${algo}-${digest}${optString}`,
|
||||
opts
|
||||
)
|
||||
// istanbul ignore else - it would be VERY strange if the string we just calculated with an algo did not have an algo or digest.
|
||||
/* istanbul ignore else - it would be VERY strange if the string we
|
||||
* just calculated with an algo did not have an algo or digest.
|
||||
*/
|
||||
if (hash.algorithm && hash.digest) {
|
||||
const hashAlgo = hash.algorithm
|
||||
if (!acc[hashAlgo]) {
|
||||
@@ -466,6 +473,7 @@ function checkData (data, sri, opts) {
|
||||
if (match || !(opts.error)) {
|
||||
return match
|
||||
} else if (typeof opts.size === 'number' && (data.length !== opts.size)) {
|
||||
/* eslint-disable-next-line max-len */
|
||||
const err = new Error(`data size mismatch when checking ${sri}.\n Wanted: ${opts.size}\n Found: ${data.length}`)
|
||||
err.code = 'EBADSIZE'
|
||||
err.found = data.length
|
||||
@@ -473,6 +481,7 @@ function checkData (data, sri, opts) {
|
||||
err.sri = sri
|
||||
throw err
|
||||
} else {
|
||||
/* eslint-disable-next-line max-len */
|
||||
const err = new Error(`Integrity checksum failed when using ${algorithm}: Wanted ${sri}, but got ${newSri}. (${data.length} bytes)`)
|
||||
err.code = 'EINTEGRITY'
|
||||
err.found = newSri
|
||||
@@ -529,11 +538,20 @@ function createIntegrity (opts) {
|
||||
digest: function () {
|
||||
const integrity = algorithms.reduce((acc, algo) => {
|
||||
const digest = hashes.shift().digest('base64')
|
||||
const hash = new Hash(`${algo}-${digest}${optString}`, opts)
|
||||
if (!acc[hash.algorithm]) {
|
||||
acc[hash.algorithm] = []
|
||||
const hash = new Hash(
|
||||
`${algo}-${digest}${optString}`,
|
||||
opts
|
||||
)
|
||||
/* istanbul ignore else - it would be VERY strange if the hash we
|
||||
* just calculated with an algo did not have an algo or digest.
|
||||
*/
|
||||
if (hash.algorithm && hash.digest) {
|
||||
const hashAlgo = hash.algorithm
|
||||
if (!acc[hashAlgo]) {
|
||||
acc[hashAlgo] = []
|
||||
}
|
||||
acc[hashAlgo].push(hash)
|
||||
}
|
||||
acc[hash.algorithm].push(hash)
|
||||
return acc
|
||||
}, new Integrity())
|
||||
|
||||
@@ -542,6 +560,18 @@ function createIntegrity (opts) {
|
||||
}
|
||||
}
|
||||
|
||||
const NODE_HASHES = crypto.getHashes()
|
||||
|
||||
// This is a Best Effort™ at a reasonable priority for hash algos
|
||||
const DEFAULT_PRIORITY = [
|
||||
'md5', 'whirlpool', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
|
||||
// TODO - it's unclear _which_ of these Node will actually use as its name
|
||||
// for the algorithm, so we guesswork it based on the OpenSSL names.
|
||||
'sha3',
|
||||
'sha3-256', 'sha3-384', 'sha3-512',
|
||||
'sha3_256', 'sha3_384', 'sha3_512',
|
||||
].filter(algo => NODE_HASHES.includes(algo))
|
||||
|
||||
function getPrioritizedHash (algo1, algo2) {
|
||||
/* eslint-disable-next-line max-len */
|
||||
return DEFAULT_PRIORITY.indexOf(algo1.toLowerCase()) >= DEFAULT_PRIORITY.indexOf(algo2.toLowerCase())
|
||||
|
||||
Reference in New Issue
Block a user