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
@@ -0,0 +1,14 @@
import React from 'react';
interface HighlightProps {
language: 'json' | 'stacktrace';
children: string | null;
}
export declare class Highlight extends React.Component<HighlightProps> {
private codeRef;
shouldComponentUpdate(nextProps: Readonly<HighlightProps>): boolean;
componentDidMount(): void;
componentDidUpdate(): void;
render(): JSX.Element;
private highlightCode;
}
export {};
@@ -0,0 +1,49 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Highlight = void 0;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const core_1 = __importDefault(require("highlight.js/lib/core"));
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const json_1 = __importDefault(require("highlight.js/lib/languages/json"));
const react_1 = __importDefault(require("react"));
const stacktrace_1 = require("./languages/stacktrace");
core_1.default.registerLanguage('json', json_1.default);
core_1.default.registerLanguage('stacktrace', stacktrace_1.stacktraceJS);
class Highlight extends react_1.default.Component {
constructor() {
super(...arguments);
this.codeRef = react_1.default.createRef();
}
shouldComponentUpdate(nextProps) {
return (nextProps.language !== this.props.language ||
(Array.isArray(this.props.children)
? this.props.children.some((item) => ![].concat(nextProps.children).includes(item))
: nextProps.children !== this.props.children));
}
componentDidMount() {
this.highlightCode();
}
componentDidUpdate() {
this.highlightCode();
}
render() {
const { language } = this.props;
return (react_1.default.createElement("pre", { ref: this.codeRef },
react_1.default.createElement("code", { className: language })));
}
highlightCode() {
var _a;
const node = (_a = this.codeRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('code');
if (node) {
node.textContent = this.props.children;
core_1.default.highlightElement(node);
}
}
}
exports.Highlight = Highlight;
//# sourceMappingURL=Highlight.js.map
@@ -0,0 +1 @@
{"version":3,"file":"Highlight.js","sourceRoot":"","sources":["../../../../src/ui/components/Highlight/Highlight.tsx"],"names":[],"mappings":";;;;;;AAAA,6DAA6D;AAC7D,aAAa;AACb,iEAAwC;AACxC,6DAA6D;AAC7D,aAAa;AACb,2EAAkD;AAClD,kDAAyB;AACzB,uDAAqD;AAErD,cAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,cAAI,CAAC,CAAA;AACnC,cAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,yBAAY,CAAC,CAAA;AAOjD,MAAa,SAAU,SAAQ,eAAK,CAAC,SAAyB;IAA9D;;QACU,YAAO,GAAG,eAAK,CAAC,SAAS,EAAkB,CAAA;IAsCrD,CAAC;IApCQ,qBAAqB,CAAC,SAAmC;QAC9D,OAAO,CACL,SAAS,CAAC,QAAQ,KAAK,IAAI,CAAC,KAAK,CAAC,QAAQ;YAC1C,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;gBACjC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CACtB,CAAC,IAAS,EAAE,EAAE,CACZ,CAAE,EAAU,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CACzD;gBACH,CAAC,CAAC,SAAS,CAAC,QAAQ,KAAK,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAChD,CAAA;IACH,CAAC;IAEM,iBAAiB;QACtB,IAAI,CAAC,aAAa,EAAE,CAAA;IACtB,CAAC;IAEM,kBAAkB;QACvB,IAAI,CAAC,aAAa,EAAE,CAAA;IACtB,CAAC;IAEM,MAAM;QACX,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,KAAK,CAAA;QAC/B,OAAO,CACL,uCAAK,GAAG,EAAE,IAAI,CAAC,OAAO;YACpB,wCAAM,SAAS,EAAE,QAAQ,GAAI,CACzB,CACP,CAAA;IACH,CAAC;IAEO,aAAa;;QACnB,MAAM,IAAI,GAAG,MAAA,IAAI,CAAC,OAAO,CAAC,OAAO,0CAAE,aAAa,CAAC,MAAM,CAAC,CAAA;QACxD,IAAI,IAAI,EAAE;YACR,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAA;YACtC,cAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAA;SAC5B;IACH,CAAC;CACF;AAvCD,8BAuCC"}
@@ -0,0 +1 @@
export declare function stacktraceJS(): any;
@@ -0,0 +1,51 @@
"use strict";
/*
Language: StacktraceJS
Author: FelixMosh
Description: Node stacktrace highlighter
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.stacktraceJS = void 0;
function stacktraceJS() {
const ERROR = {
className: 'type',
begin: /^\w*Error:\s*/,
relevance: 40,
contains: [
{
className: 'title',
begin: /.*/,
end: /$/,
excludeStart: true,
endsWithParent: true,
},
],
};
const LINE_NUMBER = {
className: 'number',
begin: ':\\d+:\\d+',
relevance: 5,
};
const TRACE_LINE = {
className: 'trace-line',
begin: /^\s*at/,
end: /$/,
keywords: 'at as async prototype anonymous function',
contains: [
{
className: 'code-path',
begin: /\(/,
end: /\)$/,
excludeEnd: true,
excludeBegin: true,
contains: [LINE_NUMBER],
},
],
};
return {
case_insensitive: true,
contains: [ERROR, TRACE_LINE, LINE_NUMBER],
};
}
exports.stacktraceJS = stacktraceJS;
//# sourceMappingURL=stacktrace.js.map
@@ -0,0 +1 @@
{"version":3,"file":"stacktrace.js","sourceRoot":"","sources":["../../../../../src/ui/components/Highlight/languages/stacktrace.ts"],"names":[],"mappings":";AAAA;;;;EAIE;;;AAEF,SAAgB,YAAY;IAC1B,MAAM,KAAK,GAAG;QACZ,SAAS,EAAE,MAAM;QACjB,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,EAAE;QACb,QAAQ,EAAE;YACR;gBACE,SAAS,EAAE,OAAO;gBAClB,KAAK,EAAE,IAAI;gBACX,GAAG,EAAE,GAAG;gBACR,YAAY,EAAE,IAAI;gBAClB,cAAc,EAAE,IAAI;aACrB;SACF;KACF,CAAA;IAED,MAAM,WAAW,GAAG;QAClB,SAAS,EAAE,QAAQ;QACnB,KAAK,EAAE,YAAY;QACnB,SAAS,EAAE,CAAC;KACb,CAAA;IAED,MAAM,UAAU,GAAG;QACjB,SAAS,EAAE,YAAY;QACvB,KAAK,EAAE,QAAQ;QACf,GAAG,EAAE,GAAG;QACR,QAAQ,EAAE,0CAA0C;QACpD,QAAQ,EAAE;YACR;gBACE,SAAS,EAAE,WAAW;gBACtB,KAAK,EAAE,IAAI;gBACX,GAAG,EAAE,KAAK;gBACV,UAAU,EAAE,IAAI;gBAChB,YAAY,EAAE,IAAI;gBAClB,QAAQ,EAAE,CAAC,WAAW,CAAC;aACxB;SACF;KACF,CAAA;IAED,OAAO;QACL,gBAAgB,EAAE,IAAI;QACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,CAAC;KAC3C,CAAA;AACH,CAAC;AA3CD,oCA2CC"}