feat: Passwordless cross-device authentication

- Arkitektur: docs/auth/passwordless-architecture.md
- Backend: iom/quixzoom-auth-service/ (FastAPI + Redis)
- Webb: quixzoom-market-pages/se/login/ (QR-kod + polling)
- App: iom/quixzoom-app/src/features/auth/ (push + deep links)

Flöde: QR-kod → app-godkännande → webb-inloggad
This commit is contained in:
Bernt
2026-07-07 07:11:50 +00:00
parent 4aa984ad74
commit 6989a98d75
61843 changed files with 5491611 additions and 872231 deletions
+188
View File
@@ -0,0 +1,188 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = formatDistance;
var formatDistanceLocale = {
lessThanXSeconds: {
standalone: {
one: 'weniger als eine Sekunde',
other: 'weniger als {{count}} Sekunden'
},
withPreposition: {
one: 'weniger als einer Sekunde',
other: 'weniger als {{count}} Sekunden'
}
},
xSeconds: {
standalone: {
one: 'eine Sekunde',
other: '{{count}} Sekunden'
},
withPreposition: {
one: 'einer Sekunde',
other: '{{count}} Sekunden'
}
},
halfAMinute: {
standalone: 'eine halbe Minute',
withPreposition: 'einer halben Minute'
},
lessThanXMinutes: {
standalone: {
one: 'weniger als eine Minute',
other: 'weniger als {{count}} Minuten'
},
withPreposition: {
one: 'weniger als einer Minute',
other: 'weniger als {{count}} Minuten'
}
},
xMinutes: {
standalone: {
one: 'eine Minute',
other: '{{count}} Minuten'
},
withPreposition: {
one: 'einer Minute',
other: '{{count}} Minuten'
}
},
aboutXHours: {
standalone: {
one: 'etwa eine Stunde',
other: 'etwa {{count}} Stunden'
},
withPreposition: {
one: 'etwa einer Stunde',
other: 'etwa {{count}} Stunden'
}
},
xHours: {
standalone: {
one: 'eine Stunde',
other: '{{count}} Stunden'
},
withPreposition: {
one: 'einer Stunde',
other: '{{count}} Stunden'
}
},
xDays: {
standalone: {
one: 'ein Tag',
other: '{{count}} Tage'
},
withPreposition: {
one: 'einem Tag',
other: '{{count}} Tagen'
}
},
aboutXWeeks: {
standalone: {
one: 'etwa ein Woche',
other: 'etwa {{count}} Wochen'
},
withPreposition: {
one: 'etwa einem Woche',
other: 'etwa {{count}} Wochen'
}
},
xWeeks: {
standalone: {
one: 'ein Woche',
other: '{{count}} Wochen'
},
withPreposition: {
one: 'einem Woche',
other: '{{count}} Wochen'
}
},
aboutXMonths: {
standalone: {
one: 'etwa ein Monat',
other: 'etwa {{count}} Monate'
},
withPreposition: {
one: 'etwa einem Monat',
other: 'etwa {{count}} Monaten'
}
},
xMonths: {
standalone: {
one: 'ein Monat',
other: '{{count}} Monate'
},
withPreposition: {
one: 'einem Monat',
other: '{{count}} Monaten'
}
},
aboutXYears: {
standalone: {
one: 'etwa ein Jahr',
other: 'etwa {{count}} Jahre'
},
withPreposition: {
one: 'etwa einem Jahr',
other: 'etwa {{count}} Jahren'
}
},
xYears: {
standalone: {
one: 'ein Jahr',
other: '{{count}} Jahre'
},
withPreposition: {
one: 'einem Jahr',
other: '{{count}} Jahren'
}
},
overXYears: {
standalone: {
one: 'mehr als ein Jahr',
other: 'mehr als {{count}} Jahre'
},
withPreposition: {
one: 'mehr als einem Jahr',
other: 'mehr als {{count}} Jahren'
}
},
almostXYears: {
standalone: {
one: 'fast ein Jahr',
other: 'fast {{count}} Jahre'
},
withPreposition: {
one: 'fast einem Jahr',
other: 'fast {{count}} Jahren'
}
}
};
function formatDistance(token, count, options) {
options = options || {};
var usageGroup = options.addSuffix ? formatDistanceLocale[token].withPreposition : formatDistanceLocale[token].standalone;
var result;
if (typeof usageGroup === 'string') {
result = usageGroup;
} else if (count === 1) {
result = usageGroup.one;
} else {
result = usageGroup.other.replace('{{count}}', count);
}
if (options.addSuffix) {
if (options.comparison > 0) {
return 'in ' + result;
} else {
return 'vor ' + result;
}
}
return result;
}
module.exports = exports.default;
+51
View File
@@ -0,0 +1,51 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _index = _interopRequireDefault(require("../../../_lib/buildFormatLongFn/index.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// DIN 5008: https://de.wikipedia.org/wiki/Datumsformat#DIN_5008
var dateFormats = {
full: 'EEEE, do MMMM y',
// Montag, 7. Januar 2018
long: 'do MMMM y',
// 7. Januar 2018
medium: 'do MMM. y',
// 7. Jan. 2018
short: 'dd.MM.y' // 07.01.2018
};
var timeFormats = {
full: 'HH:mm:ss zzzz',
long: 'HH:mm:ss z',
medium: 'HH:mm:ss',
short: 'HH:mm'
};
var dateTimeFormats = {
full: "{{date}} 'um' {{time}}",
long: "{{date}} 'um' {{time}}",
medium: '{{date}} {{time}}',
short: '{{date}} {{time}}'
};
var formatLong = {
date: (0, _index.default)({
formats: dateFormats,
defaultWidth: 'full'
}),
time: (0, _index.default)({
formats: timeFormats,
defaultWidth: 'full'
}),
dateTime: (0, _index.default)({
formats: dateTimeFormats,
defaultWidth: 'full'
})
};
var _default = formatLong;
exports.default = _default;
module.exports = exports.default;
+20
View File
@@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = formatRelative;
var formatRelativeLocale = {
lastWeek: "'letzten' eeee 'um' p",
yesterday: "'gestern um' p",
today: "'heute um' p",
tomorrow: "'morgen um' p",
nextWeek: "eeee 'um' p",
other: 'P'
};
function formatRelative(token, _date, _baseDate, _options) {
return formatRelativeLocale[token];
}
module.exports = exports.default;
+138
View File
@@ -0,0 +1,138 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _index = _interopRequireDefault(require("../../../_lib/buildLocalizeFn/index.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var eraValues = {
narrow: ['v.Chr.', 'n.Chr.'],
abbreviated: ['v.Chr.', 'n.Chr.'],
wide: ['vor Christus', 'nach Christus']
};
var quarterValues = {
narrow: ['1', '2', '3', '4'],
abbreviated: ['Q1', 'Q2', 'Q3', 'Q4'],
wide: ['1. Quartal', '2. Quartal', '3. Quartal', '4. Quartal'] // Note: in German, the names of days of the week and months are capitalized.
// If you are making a new locale based on this one, check if the same is true for the language you're working on.
// Generally, formatted dates should look like they are in the middle of a sentence,
// e.g. in Spanish language the weekdays and months should be in the lowercase.
};
var monthValues = {
narrow: ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D'],
abbreviated: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],
wide: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember']
};
var dayValues = {
narrow: ['S', 'M', 'D', 'M', 'D', 'F', 'S'],
short: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
abbreviated: ['So.', 'Mo.', 'Di.', 'Mi.', 'Do.', 'Fr.', 'Sa.'],
wide: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'] // https://www.unicode.org/cldr/charts/32/summary/de.html#1881
};
var dayPeriodValues = {
narrow: {
am: 'vm.',
pm: 'nm.',
midnight: 'Mitternacht',
noon: 'Mittag',
morning: 'Morgen',
afternoon: 'Nachm.',
evening: 'Abend',
night: 'Nacht'
},
abbreviated: {
am: 'vorm.',
pm: 'nachm.',
midnight: 'Mitternacht',
noon: 'Mittag',
morning: 'Morgen',
afternoon: 'Nachmittag',
evening: 'Abend',
night: 'Nacht'
},
wide: {
am: 'vormittags',
pm: 'nachmittags',
midnight: 'Mitternacht',
noon: 'Mittag',
morning: 'Morgen',
afternoon: 'Nachmittag',
evening: 'Abend',
night: 'Nacht'
}
};
var formattingDayPeriodValues = {
narrow: {
am: 'vm.',
pm: 'nm.',
midnight: 'Mitternacht',
noon: 'Mittag',
morning: 'morgens',
afternoon: 'nachm.',
evening: 'abends',
night: 'nachts'
},
abbreviated: {
am: 'vorm.',
pm: 'nachm.',
midnight: 'Mitternacht',
noon: 'Mittag',
morning: 'morgens',
afternoon: 'nachmittags',
evening: 'abends',
night: 'nachts'
},
wide: {
am: 'vormittags',
pm: 'nachmittags',
midnight: 'Mitternacht',
noon: 'Mittag',
morning: 'morgens',
afternoon: 'nachmittags',
evening: 'abends',
night: 'nachts'
}
};
function ordinalNumber(dirtyNumber, _dirtyOptions) {
var number = Number(dirtyNumber);
return number + '.';
}
var localize = {
ordinalNumber: ordinalNumber,
era: (0, _index.default)({
values: eraValues,
defaultWidth: 'wide'
}),
quarter: (0, _index.default)({
values: quarterValues,
defaultWidth: 'wide',
argumentCallback: function (quarter) {
return Number(quarter) - 1;
}
}),
month: (0, _index.default)({
values: monthValues,
defaultWidth: 'wide'
}),
day: (0, _index.default)({
values: dayValues,
defaultWidth: 'wide'
}),
dayPeriod: (0, _index.default)({
values: dayPeriodValues,
defaultWidth: 'wide',
formattingValues: formattingDayPeriodValues,
defaultFormattingWidth: 'wide'
})
};
var _default = localize;
exports.default = _default;
module.exports = exports.default;
+113
View File
@@ -0,0 +1,113 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _index = _interopRequireDefault(require("../../../_lib/buildMatchPatternFn/index.js"));
var _index2 = _interopRequireDefault(require("../../../_lib/buildMatchFn/index.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var matchOrdinalNumberPattern = /^(\d+)(\.)?/i;
var parseOrdinalNumberPattern = /\d+/i;
var matchEraPatterns = {
narrow: /^(v\.? ?Chr\.?|n\.? ?Chr\.?)/i,
abbreviated: /^(v\.? ?Chr\.?|n\.? ?Chr\.?)/i,
wide: /^(vor Christus|vor unserer Zeitrechnung|nach Christus|unserer Zeitrechnung)/i
};
var parseEraPatterns = {
any: [/^v/i, /^n/i]
};
var matchQuarterPatterns = {
narrow: /^[1234]/i,
abbreviated: /^q[1234]/i,
wide: /^[1234](\.)? Quartal/i
};
var parseQuarterPatterns = {
any: [/1/i, /2/i, /3/i, /4/i]
};
var matchMonthPatterns = {
narrow: /^[jfmasond]/i,
abbreviated: /^(jan|feb|mär|apr|mai|jun|jul|aug|sep|okt|nov|dez)/i,
wide: /^(januar|februar|märz|april|mai|juni|juli|august|september|oktober|november|dezember)/i
};
var parseMonthPatterns = {
narrow: [/^j/i, /^f/i, /^m/i, /^a/i, /^m/i, /^j/i, /^j/i, /^a/i, /^s/i, /^o/i, /^n/i, /^d/i],
any: [/^ja/i, /^f/i, /^mär/i, /^ap/i, /^mai/i, /^jun/i, /^jul/i, /^au/i, /^s/i, /^o/i, /^n/i, /^d/i]
};
var matchDayPatterns = {
narrow: /^[smdmf]/i,
short: /^(so|mo|di|mi|do|fr|sa)/i,
abbreviated: /^(son?|mon?|die?|mit?|don?|fre?|sam?)\.?/i,
wide: /^(sonntag|montag|dienstag|mittwoch|donnerstag|freitag|samstag)/i
};
var parseDayPatterns = {
any: [/^so/i, /^mo/i, /^di/i, /^mi/i, /^do/i, /^f/i, /^sa/i]
};
var matchDayPeriodPatterns = {
narrow: /^(vm\.?|nm\.?|Mitternacht|Mittag|morgens|nachm\.?|abends|nachts)/i,
abbreviated: /^(vorm\.?|nachm\.?|Mitternacht|Mittag|morgens|nachm\.?|abends|nachts)/i,
wide: /^(vormittags|nachmittags|Mitternacht|Mittag|morgens|nachmittags|abends|nachts)/i
};
var parseDayPeriodPatterns = {
any: {
am: /^v/i,
pm: /^n/i,
midnight: /^Mitte/i,
noon: /^Mitta/i,
morning: /morgens/i,
afternoon: /nachmittags/i,
// will never be matched. Afternoon is matched by `pm`
evening: /abends/i,
night: /nachts/i // will never be matched. Night is matched by `pm`
}
};
var match = {
ordinalNumber: (0, _index.default)({
matchPattern: matchOrdinalNumberPattern,
parsePattern: parseOrdinalNumberPattern,
valueCallback: function (value) {
return parseInt(value, 10);
}
}),
era: (0, _index2.default)({
matchPatterns: matchEraPatterns,
defaultMatchWidth: 'wide',
parsePatterns: parseEraPatterns,
defaultParseWidth: 'any'
}),
quarter: (0, _index2.default)({
matchPatterns: matchQuarterPatterns,
defaultMatchWidth: 'wide',
parsePatterns: parseQuarterPatterns,
defaultParseWidth: 'any',
valueCallback: function (index) {
return index + 1;
}
}),
month: (0, _index2.default)({
matchPatterns: matchMonthPatterns,
defaultMatchWidth: 'wide',
parsePatterns: parseMonthPatterns,
defaultParseWidth: 'any'
}),
day: (0, _index2.default)({
matchPatterns: matchDayPatterns,
defaultMatchWidth: 'wide',
parsePatterns: parseDayPatterns,
defaultParseWidth: 'any'
}),
dayPeriod: (0, _index2.default)({
matchPatterns: matchDayPeriodPatterns,
defaultMatchWidth: 'wide',
parsePatterns: parseDayPeriodPatterns,
defaultParseWidth: 'any'
})
};
var _default = match;
exports.default = _default;
module.exports = exports.default;