diff --git a/backend/controllers/memberController.js b/backend/controllers/memberController.js index 2e9864e..35829a4 100644 --- a/backend/controllers/memberController.js +++ b/backend/controllers/memberController.js @@ -34,11 +34,11 @@ const getWaitingApprovals = async(req, res) => { const setClubMembers = async (req, res) => { try { const { id: memberId, firstname: firstName, lastname: lastName, street, city, birthdate, phone, email, active, - testMembership, picsInInternetAllowed } = req.body; + testMembership, picsInInternetAllowed, gender } = req.body; const { id: clubId } = req.params; const { authcode: userToken } = req.headers; const addResult = await MemberService.setClubMember(userToken, clubId, memberId, firstName, lastName, street, city, birthdate, - phone, email, active, testMembership, picsInInternetAllowed); + phone, email, active, testMembership, picsInInternetAllowed, gender); res.status(addResult.status || 500).json(addResult.response); } catch (error) { console.error('[setClubMembers] - Error:', error); diff --git a/backend/controllers/officialTournamentController.js b/backend/controllers/officialTournamentController.js new file mode 100644 index 0000000..ff516a0 --- /dev/null +++ b/backend/controllers/officialTournamentController.js @@ -0,0 +1,319 @@ +import { createRequire } from 'module'; +const require = createRequire(import.meta.url); +const pdfParse = require('pdf-parse/lib/pdf-parse.js'); +import { checkAccess } from '../utils/userUtils.js'; +import OfficialTournament from '../models/OfficialTournament.js'; +import OfficialCompetition from '../models/OfficialCompetition.js'; + +// In-Memory Store (einfacher Start); später DB-Modell +const parsedTournaments = new Map(); // key: id, value: { id, clubId, rawText, parsedData } +let seq = 1; + +export const uploadTournamentPdf = async (req, res) => { + try { + const { authcode: userToken } = req.headers; + const { clubId } = req.params; + await checkAccess(userToken, clubId); + if (!req.file || !req.file.buffer) return res.status(400).json({ error: 'No pdf provided' }); + const data = await pdfParse(req.file.buffer); + const parsed = parseTournamentText(data.text); + const t = await OfficialTournament.create({ + clubId, + title: parsed.title || null, + eventDate: parsed.termin || null, + organizer: null, + host: null, + venues: JSON.stringify(parsed.austragungsorte || []), + competitionTypes: JSON.stringify(parsed.konkurrenztypen || []), + registrationDeadlines: JSON.stringify(parsed.meldeschluesse || []), + }); + // competitions persistieren + for (const c of parsed.competitions || []) { + // Korrigiere Fehlzuordnung: Wenn die Zeile mit "Stichtag" fälschlich in performanceClass steht + let performanceClass = c.leistungsklasse || c.performanceClass || null; + let cutoffDate = c.stichtag || c.cutoffDate || null; + if (performanceClass && /^stichtag\b/i.test(performanceClass)) { + cutoffDate = performanceClass.replace(/^stichtag\s*:?\s*/i, '').trim(); + performanceClass = null; + } + await OfficialCompetition.create({ + tournamentId: t.id, + ageClassCompetition: c.altersklasseWettbewerb || c.ageClassCompetition || null, + performanceClass, + startTime: c.startzeit || c.startTime || null, + registrationDeadlineDate: c.meldeschlussDatum || c.registrationDeadlineDate || null, + registrationDeadlineOnline: c.meldeschlussOnline || c.registrationDeadlineOnline || null, + cutoffDate, + ttrRelevant: c.ttrRelevant || null, + openTo: c.offenFuer || c.openTo || null, + preliminaryRound: c.vorrunde || c.preliminaryRound || null, + finalRound: c.endrunde || c.finalRound || null, + maxParticipants: c.maxTeilnehmer || c.maxParticipants || null, + entryFee: c.startgeld || c.entryFee || null, + }); + } + res.status(201).json({ id: String(t.id) }); + } catch (e) { + console.error('[uploadTournamentPdf] Error:', e); + res.status(500).json({ error: 'Failed to parse pdf' }); + } +}; + +export const getParsedTournament = async (req, res) => { + try { + const { authcode: userToken } = req.headers; + const { clubId, id } = req.params; + await checkAccess(userToken, clubId); + const t = await OfficialTournament.findOne({ where: { id, clubId } }); + if (!t) return res.status(404).json({ error: 'not found' }); + const comps = await OfficialCompetition.findAll({ where: { tournamentId: id } }); + const competitions = comps.map((c) => { + const j = c.toJSON(); + return { + id: j.id, + tournamentId: j.tournamentId, + ageClassCompetition: j.ageClassCompetition || null, + performanceClass: j.performanceClass || null, + startTime: j.startTime || null, + registrationDeadlineDate: j.registrationDeadlineDate || null, + registrationDeadlineOnline: j.registrationDeadlineOnline || null, + cutoffDate: j.cutoffDate || null, + ttrRelevant: j.ttrRelevant || null, + openTo: j.openTo || null, + preliminaryRound: j.preliminaryRound || null, + finalRound: j.finalRound || null, + maxParticipants: j.maxParticipants || null, + entryFee: j.entryFee || null, + // Legacy Felder zusätzlich, falls Frontend sie noch nutzt + altersklasseWettbewerb: j.ageClassCompetition || null, + leistungsklasse: j.performanceClass || null, + startzeit: j.startTime || null, + meldeschlussDatum: j.registrationDeadlineDate || null, + meldeschlussOnline: j.registrationDeadlineOnline || null, + stichtag: j.cutoffDate || null, + offenFuer: j.openTo || null, + vorrunde: j.preliminaryRound || null, + endrunde: j.finalRound || null, + maxTeilnehmer: j.maxParticipants || null, + startgeld: j.entryFee || null, + }; + }); + res.status(200).json({ + id: String(t.id), + clubId: String(t.clubId), + parsedData: { + title: t.title, + termin: t.eventDate, + austragungsorte: JSON.parse(t.venues || '[]'), + konkurrenztypen: JSON.parse(t.competitionTypes || '[]'), + meldeschluesse: JSON.parse(t.registrationDeadlines || '[]'), + competitions, + }, + }); + } catch (e) { + res.status(500).json({ error: 'Failed to fetch parsed tournament' }); + } +}; + +export const listOfficialTournaments = async (req, res) => { + try { + const { authcode: userToken } = req.headers; + const { clubId } = req.params; + await checkAccess(userToken, clubId); + const list = await OfficialTournament.findAll({ where: { clubId } }); + res.status(200).json(list); + } catch (e) { + res.status(500).json({ error: 'Failed to list tournaments' }); + } +}; + +export const deleteOfficialTournament = async (req, res) => { + try { + const { authcode: userToken } = req.headers; + const { clubId, id } = req.params; + await checkAccess(userToken, clubId); + const t = await OfficialTournament.findOne({ where: { id, clubId } }); + if (!t) return res.status(404).json({ error: 'not found' }); + await OfficialCompetition.destroy({ where: { tournamentId: id } }); + await OfficialTournament.destroy({ where: { id } }); + res.status(204).send(); + } catch (e) { + res.status(500).json({ error: 'Failed to delete tournament' }); + } +}; + +function parseTournamentText(text) { + const lines = text.split(/\r?\n/); + const normLines = lines.map(l => l.replace(/\s+/g, ' ').trim()); + + const findTitle = () => { + const idx = normLines.findIndex(l => /Kreiseinzelmeisterschaften/i.test(l)); + return idx >= 0 ? normLines[idx] : null; + }; + + const extractBlockAfter = (labels, multiline = false) => { + const idx = normLines.findIndex(l => labels.some(lb => l.toLowerCase().startsWith(lb))); + if (idx === -1) return multiline ? [] : null; + const line = normLines[idx]; + const afterColon = line.includes(':') ? line.split(':').slice(1).join(':').trim() : ''; + if (!multiline) { + if (afterColon) return afterColon; + // sonst nächste nicht-leere Zeile + for (let i = idx + 1; i < normLines.length; i++) { + if (normLines[i]) return normLines[i]; + } + return null; + } + // multiline bis zur nächsten Leerzeile oder nächsten bekannten Section + const out = []; + if (afterColon) out.push(afterColon); + for (let i = idx + 1; i < normLines.length; i++) { + const ln = normLines[i]; + if (!ln) break; + if (/^(termin|austragungsort|austragungsorte|konkurrenz|konkurrenzen|konkurrenztypen|meldeschluss|altersklassen|startzeiten)/i.test(ln)) break; + out.push(ln); + } + return out; + }; + + const extractAllMatches = (regex) => { + const results = []; + for (const l of normLines) { + const m = l.match(regex); + if (m) results.push(m); + } + return results; + }; + + const title = findTitle(); + const termin = extractBlockAfter(['termin', 'termin '], false); + const austragungsorte = extractBlockAfter(['austragungsort', 'austragungsorte'], true); + let konkurrenzRaw = extractBlockAfter(['konkurrenz', 'konkurrenzen', 'konkurrenztypen'], true); + if (konkurrenzRaw && !Array.isArray(konkurrenzRaw)) konkurrenzRaw = [konkurrenzRaw]; + const konkurrenztypen = (konkurrenzRaw || []).flatMap(l => l.split(/[;,]/)).map(s => s.trim()).filter(Boolean); + + // Meldeschlüsse mit Position und Zuordnung zu AK ermitteln + const meldeschluesseRaw = []; + for (let i = 0; i < normLines.length; i++) { + const l = normLines[i]; + const m = l.match(/meldeschluss\s*:?\s*(.+)$/i); + if (m) meldeschluesseRaw.push({ line: i, value: m[1].trim() }); + } + + let altersRaw = extractBlockAfter(['altersklassen', 'altersklasse'], true); + if (altersRaw && !Array.isArray(altersRaw)) altersRaw = [altersRaw]; + const altersklassen = (altersRaw || []).flatMap(l => l.split(/[;,]/)).map(s => s.trim()).filter(Boolean); + + // Wettbewerbe/Konkurrenzen parsen (Block ab "3. Konkurrenzen") + const competitions = []; + const konkIdx = normLines.findIndex(l => /^\s*3\.?\s+Konkurrenzen/i.test(l) || /^Konkurrenzen\b/i.test(l)); + // Bestimme Start-Sektionsnummer (z. B. 3 bei "3. Konkurrenzen"), fallback 3 + const startSectionNum = (() => { + if (konkIdx === -1) return 3; + const m = normLines[konkIdx].match(/^\s*(\d+)\./); + return m ? parseInt(m[1], 10) : 3; + })(); + const nextSectionIdx = () => { + for (let i = konkIdx + 1; i < normLines.length; i++) { + const m = normLines[i].match(/^\s*(\d+)\.\s+/); + if (m) { + const num = parseInt(m[1], 10); + if (!Number.isNaN(num) && num > startSectionNum) return i; + } + // Hinweis: Seitenfußzeilen wie "nu.Dokument ..." ignorieren wir, damit mehrseitige Blöcke nicht abbrechen + } + return normLines.length; + }; + if (konkIdx !== -1) { + const endIdx = nextSectionIdx(); + let i = konkIdx + 1; + while (i < endIdx) { + const line = normLines[i]; + if (/^Altersklasse\/Wettbewerb\s*:/i.test(line)) { + const comp = {}; + comp.altersklasseWettbewerb = line.split(':').slice(1).join(':').trim(); + i++; + while (i < endIdx && !/^Altersklasse\/Wettbewerb\s*:/i.test(normLines[i])) { + const ln = normLines[i]; + const m = ln.match(/^([^:]+):\s*(.*)$/); + if (m) { + const key = m[1].trim().toLowerCase(); + const val = m[2].trim(); + if (key.startsWith('leistungsklasse')) comp.leistungsklasse = val; + else if (key === 'startzeit') { + // Erwartet: 20.09.2025 13:30 Uhr -> wir extrahieren Datum+Zeit + const sm = val.match(/(\d{2}\.\d{2}\.\d{4})\s+(\d{1,2}:\d{2})/); + comp.startzeit = sm ? `${sm[1]} ${sm[2]}` : val; + } + else if (key.startsWith('meldeschluss datum')) comp.meldeschlussDatum = val; + else if (key.startsWith('meldeschluss online')) comp.meldeschlussOnline = val; + else if (key === 'stichtag') comp.stichtag = val; + else if (key === 'ttr-relevant') comp.ttrRelevant = val; + else if (key === 'offen für') comp.offenFuer = val; + else if (key.startsWith('austragungssys. vorrunde')) comp.vorrunde = val; + else if (key.startsWith('austragungssys. endrunde')) comp.endrunde = val; + else if (key.startsWith('max. teilnehmerzahl')) comp.maxTeilnehmer = val; + else if (key === 'startgeld') comp.startgeld = val; + } + i++; + } + competitions.push(comp); + continue; // schon auf nächster Zeile + } + i++; + } + } + + // Altersklassen-Positionen im Text (zur Zuordnung von Meldeschlüssen) + const akPositions = []; + for (let i = 0; i < normLines.length; i++) { + const l = normLines[i]; + const m = l.match(/\b(U\d+|AK\s*\d+)\b/i); + if (m) akPositions.push({ line: i, ak: m[1].toUpperCase().replace(/\s+/g, '') }); + } + + const meldeschluesseByAk = {}; + for (const ms of meldeschluesseRaw) { + // Nächste AK im Umkreis von 3 Zeilen suchen + let best = null; + let bestDist = Infinity; + for (const ak of akPositions) { + const dist = Math.abs(ak.line - ms.line); + if (dist < bestDist && dist <= 3) { best = ak; bestDist = dist; } + } + if (best) { + if (!meldeschluesseByAk[best.ak]) meldeschluesseByAk[best.ak] = new Set(); + meldeschluesseByAk[best.ak].add(ms.value); + } + } + + // Dedup global + const meldeschluesse = Array.from(new Set(meldeschluesseRaw.map(x => x.value))); + // Sets zu Arrays + const meldeschluesseByAkOut = Object.fromEntries(Object.entries(meldeschluesseByAk).map(([k,v]) => [k, Array.from(v)])); + + // Vorhandene einfache Personenerkennung (optional, zu Analysezwecken) + const entries = []; + for (const l of normLines) { + const m = l.match(/^([A-Za-zÄÖÜäöüß\-\s']{3,})(?:\s+\((m|w|d)\))?$/i); + if (m && /\s/.test(m[1])) { + entries.push({ name: m[1].trim(), genderHint: m[2] || null }); + } + } + + return { + title, + termin, + austragungsorte, + konkurrenztypen, + meldeschluesse, + meldeschluesseByAk: meldeschluesseByAkOut, + altersklassen, + startzeiten: {}, + competitions, + entries, + debug: { normLines }, + }; +} + + diff --git a/backend/models/Member.js b/backend/models/Member.js index f61ebdf..7d60fed 100644 --- a/backend/models/Member.js +++ b/backend/models/Member.js @@ -122,6 +122,12 @@ const Member = sequelize.define('Member', { allowNull: false, default: false, } + , + gender: { + type: DataTypes.ENUM('male','female','diverse','unknown'), + allowNull: true, + defaultValue: 'unknown' + } }, { underscored: true, sequelize, diff --git a/backend/models/OfficialCompetition.js b/backend/models/OfficialCompetition.js new file mode 100644 index 0000000..2712a30 --- /dev/null +++ b/backend/models/OfficialCompetition.js @@ -0,0 +1,28 @@ +import { DataTypes } from 'sequelize'; +import sequelize from '../database.js'; + +const OfficialCompetition = sequelize.define('OfficialCompetition', { + id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, + tournamentId: { type: DataTypes.INTEGER, allowNull: false }, + // Englische Attributnamen, gemappt auf bestehende DB-Spalten + ageClassCompetition: { type: DataTypes.STRING, allowNull: true, field: 'age_class_competition' }, + performanceClass: { type: DataTypes.STRING, allowNull: true, field: 'performance_class' }, + startTime: { type: DataTypes.STRING, allowNull: true, field: 'start_time' }, + registrationDeadlineDate: { type: DataTypes.STRING, allowNull: true, field: 'registration_deadline_date' }, + registrationDeadlineOnline: { type: DataTypes.STRING, allowNull: true, field: 'registration_deadline_online' }, + cutoffDate: { type: DataTypes.STRING, allowNull: true, field: 'cutoff_date' }, + ttrRelevant: { type: DataTypes.STRING, allowNull: true }, + openTo: { type: DataTypes.STRING, allowNull: true, field: 'open_to' }, + preliminaryRound: { type: DataTypes.STRING, allowNull: true, field: 'preliminary_round' }, + finalRound: { type: DataTypes.STRING, allowNull: true, field: 'final_round' }, + maxParticipants: { type: DataTypes.STRING, allowNull: true, field: 'max_participants' }, + entryFee: { type: DataTypes.STRING, allowNull: true, field: 'entry_fee' }, +}, { + tableName: 'official_competitions', + timestamps: true, + underscored: true, +}); + +export default OfficialCompetition; + + diff --git a/backend/models/OfficialTournament.js b/backend/models/OfficialTournament.js new file mode 100644 index 0000000..69b582c --- /dev/null +++ b/backend/models/OfficialTournament.js @@ -0,0 +1,22 @@ +import { DataTypes } from 'sequelize'; +import sequelize from '../database.js'; + +const OfficialTournament = sequelize.define('OfficialTournament', { + id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, + clubId: { type: DataTypes.INTEGER, allowNull: false }, + title: { type: DataTypes.STRING, allowNull: true }, + eventDate: { type: DataTypes.STRING, allowNull: true }, + organizer: { type: DataTypes.STRING, allowNull: true }, + host: { type: DataTypes.STRING, allowNull: true }, + venues: { type: DataTypes.TEXT, allowNull: true }, // JSON.stringify(Array) + competitionTypes: { type: DataTypes.TEXT, allowNull: true }, // JSON.stringify(Array) + registrationDeadlines: { type: DataTypes.TEXT, allowNull: true }, // JSON.stringify(Array) +}, { + tableName: 'official_tournaments', + timestamps: true, + underscored: true, +}); + +export default OfficialTournament; + + diff --git a/backend/models/index.js b/backend/models/index.js index 0500b30..0473078 100644 --- a/backend/models/index.js +++ b/backend/models/index.js @@ -30,6 +30,11 @@ import TournamentMatch from './TournamentMatch.js'; import TournamentResult from './TournamentResult.js'; import Accident from './Accident.js'; import UserToken from './UserToken.js'; +import OfficialTournament from './OfficialTournament.js'; +import OfficialCompetition from './OfficialCompetition.js'; +// Official tournaments relations +OfficialTournament.hasMany(OfficialCompetition, { foreignKey: 'tournamentId', as: 'competitions' }); +OfficialCompetition.belongsTo(OfficialTournament, { foreignKey: 'tournamentId', as: 'tournament' }); User.hasMany(Log, { foreignKey: 'userId' }); Log.belongsTo(User, { foreignKey: 'userId' }); @@ -223,4 +228,6 @@ export { TournamentResult, Accident, UserToken, + OfficialTournament, + OfficialCompetition, }; diff --git a/backend/node_modules/.package-lock.json b/backend/node_modules/.package-lock.json index 48ff857..152f705 100644 --- a/backend/node_modules/.package-lock.json +++ b/backend/node_modules/.package-lock.json @@ -4,6 +4,17 @@ "lockfileVersion": 3, "requires": true, "packages": { + "node_modules/@emnapi/runtime": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz", + "integrity": "sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==", + "ideallyInert": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -180,6 +191,137 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "ideallyInert": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "ideallyInert": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "ideallyInert": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "ideallyInert": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "ideallyInert": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "ideallyInert": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "ideallyInert": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-libvips-linux-x64": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", @@ -196,6 +338,23 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "ideallyInert": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", @@ -212,6 +371,75 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "ideallyInert": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "ideallyInert": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "ideallyInert": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" + } + }, "node_modules/@img/sharp-linux-x64": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", @@ -234,6 +462,29 @@ "@img/sharp-libvips-linux-x64": "1.0.4" } }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "ideallyInert": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, "node_modules/@img/sharp-linuxmusl-x64": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", @@ -256,6 +507,66 @@ "@img/sharp-libvips-linuxmusl-x64": "1.0.4" } }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "ideallyInert": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "ideallyInert": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "ideallyInert": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@mapbox/node-pre-gyp": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", @@ -573,9 +884,10 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -848,9 +1160,10 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -879,10 +1192,11 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "path-key": "^3.1.0", @@ -1265,16 +1579,17 @@ } }, "node_modules/express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -1288,7 +1603,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -1303,6 +1618,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/encodeurl": { @@ -1477,6 +1796,21 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "ideallyInert": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -2302,6 +2636,12 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" }, + "node_modules/node-ensure": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/node-ensure/-/node-ensure-0.0.0.tgz", + "integrity": "sha512-DRI60hzo2oKN1ma0ckc6nQWlHU69RH6xN0sjQTjMpChPfTYvKZdcQFfdYK2RWbJcKyUizSIy/l8OTGxMAM1QDw==", + "license": "MIT" + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -2554,9 +2894,37 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/pdf-parse": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pdf-parse/-/pdf-parse-1.1.1.tgz", + "integrity": "sha512-v6ZJ/efsBpGrGGknjtq9J/oC8tZWq0KWL5vQrk2GlzLEQPUDB1ex+13Rmidl1neNN358Jn9EHZw5y07FFtaC7A==", + "license": "MIT", + "dependencies": { + "debug": "^3.1.0", + "node-ensure": "^0.0.0" + }, + "engines": { + "node": ">=6.8.1" + } + }, + "node_modules/pdf-parse/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/pdf-parse/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/pg-connection-string": { @@ -3240,6 +3608,14 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "ideallyInert": true, + "license": "0BSD", + "optional": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/backend/node_modules/brace-expansion/index.js b/backend/node_modules/brace-expansion/index.js index 0478be8..bd19fe6 100644 --- a/backend/node_modules/brace-expansion/index.js +++ b/backend/node_modules/brace-expansion/index.js @@ -109,7 +109,7 @@ function expand(str, isTop) { var isOptions = m.body.indexOf(',') >= 0; if (!isSequence && !isOptions) { // {a},b} - if (m.post.match(/,.*\}/)) { + if (m.post.match(/,(?!,).*\}/)) { str = m.pre + '{' + m.body + escClose + m.post; return expand(str); } diff --git a/backend/node_modules/brace-expansion/package.json b/backend/node_modules/brace-expansion/package.json index a18faa8..3447888 100644 --- a/backend/node_modules/brace-expansion/package.json +++ b/backend/node_modules/brace-expansion/package.json @@ -1,7 +1,7 @@ { "name": "brace-expansion", "description": "Brace expansion as known from sh/bash", - "version": "1.1.11", + "version": "1.1.12", "repository": { "type": "git", "url": "git://github.com/juliangruber/brace-expansion.git" @@ -43,5 +43,8 @@ "iphone/6.0..latest", "android-browser/4.2..latest" ] + }, + "publishConfig": { + "tag": "1.x" } } diff --git a/backend/node_modules/cookie/HISTORY.md b/backend/node_modules/cookie/HISTORY.md deleted file mode 100644 index 41ae4b0..0000000 --- a/backend/node_modules/cookie/HISTORY.md +++ /dev/null @@ -1,147 +0,0 @@ -0.6.0 / 2023-11-06 -================== - - * Add `partitioned` option - -0.5.0 / 2022-04-11 -================== - - * Add `priority` option - * Fix `expires` option to reject invalid dates - * perf: improve default decode speed - * perf: remove slow string split in parse - -0.4.2 / 2022-02-02 -================== - - * perf: read value only when assigning in parse - * perf: remove unnecessary regexp in parse - -0.4.1 / 2020-04-21 -================== - - * Fix `maxAge` option to reject invalid values - -0.4.0 / 2019-05-15 -================== - - * Add `SameSite=None` support - -0.3.1 / 2016-05-26 -================== - - * Fix `sameSite: true` to work with draft-7 clients - - `true` now sends `SameSite=Strict` instead of `SameSite` - -0.3.0 / 2016-05-26 -================== - - * Add `sameSite` option - - Replaces `firstPartyOnly` option, never implemented by browsers - * Improve error message when `encode` is not a function - * Improve error message when `expires` is not a `Date` - -0.2.4 / 2016-05-20 -================== - - * perf: enable strict mode - * perf: use for loop in parse - * perf: use string concatenation for serialization - -0.2.3 / 2015-10-25 -================== - - * Fix cookie `Max-Age` to never be a floating point number - -0.2.2 / 2015-09-17 -================== - - * Fix regression when setting empty cookie value - - Ease the new restriction, which is just basic header-level validation - * Fix typo in invalid value errors - -0.2.1 / 2015-09-17 -================== - - * Throw on invalid values provided to `serialize` - - Ensures the resulting string is a valid HTTP header value - -0.2.0 / 2015-08-13 -================== - - * Add `firstPartyOnly` option - * Throw better error for invalid argument to parse - * perf: hoist regular expression - -0.1.5 / 2015-09-17 -================== - - * Fix regression when setting empty cookie value - - Ease the new restriction, which is just basic header-level validation - * Fix typo in invalid value errors - -0.1.4 / 2015-09-17 -================== - - * Throw better error for invalid argument to parse - * Throw on invalid values provided to `serialize` - - Ensures the resulting string is a valid HTTP header value - -0.1.3 / 2015-05-19 -================== - - * Reduce the scope of try-catch deopt - * Remove argument reassignments - -0.1.2 / 2014-04-16 -================== - - * Remove unnecessary files from npm package - -0.1.1 / 2014-02-23 -================== - - * Fix bad parse when cookie value contained a comma - * Fix support for `maxAge` of `0` - -0.1.0 / 2013-05-01 -================== - - * Add `decode` option - * Add `encode` option - -0.0.6 / 2013-04-08 -================== - - * Ignore cookie parts missing `=` - -0.0.5 / 2012-10-29 -================== - - * Return raw cookie value if value unescape errors - -0.0.4 / 2012-06-21 -================== - - * Use encode/decodeURIComponent for cookie encoding/decoding - - Improve server/client interoperability - -0.0.3 / 2012-06-06 -================== - - * Only escape special characters per the cookie RFC - -0.0.2 / 2012-06-01 -================== - - * Fix `maxAge` option to not throw error - -0.0.1 / 2012-05-28 -================== - - * Add more tests - -0.0.0 / 2012-05-28 -================== - - * Initial release diff --git a/backend/node_modules/cookie/index.js b/backend/node_modules/cookie/index.js index 03d4c38..51a58cb 100644 --- a/backend/node_modules/cookie/index.js +++ b/backend/node_modules/cookie/index.js @@ -23,14 +23,66 @@ exports.serialize = serialize; var __toString = Object.prototype.toString /** - * RegExp to match field-content in RFC 7230 sec 3.2 + * RegExp to match cookie-name in RFC 6265 sec 4.1.1 + * This refers out to the obsoleted definition of token in RFC 2616 sec 2.2 + * which has been replaced by the token definition in RFC 7230 appendix B. * - * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] - * field-vchar = VCHAR / obs-text - * obs-text = %x80-FF + * cookie-name = token + * token = 1*tchar + * tchar = "!" / "#" / "$" / "%" / "&" / "'" / + * "*" / "+" / "-" / "." / "^" / "_" / + * "`" / "|" / "~" / DIGIT / ALPHA */ -var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/; +var cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/; + +/** + * RegExp to match cookie-value in RFC 6265 sec 4.1.1 + * + * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) + * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E + * ; US-ASCII characters excluding CTLs, + * ; whitespace DQUOTE, comma, semicolon, + * ; and backslash + */ + +var cookieValueRegExp = /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/; + +/** + * RegExp to match domain-value in RFC 6265 sec 4.1.1 + * + * domain-value = + * ; defined in [RFC1034], Section 3.5, as + * ; enhanced by [RFC1123], Section 2.1 + * =