feat(core): update session, security system and QR exchange

- Removed session creation and Lightning payment logic
- Refactored security system:
  * no more restrictions
  * all systems enabled on session creation
- Improved QR code exchange for mobile devices
This commit is contained in:
lockbitchat
2025-09-23 20:01:02 -04:00
parent 804b384271
commit 34094956b7
396 changed files with 126516 additions and 11881 deletions

7
node_modules/html5-qrcode/src/camera/core-impl.d.ts generated vendored Normal file
View File

@@ -0,0 +1,7 @@
import { Camera, CameraRenderingOptions, RenderedCamera, RenderingCallbacks } from "./core";
export declare class CameraImpl implements Camera {
private readonly mediaStream;
private constructor();
render(parentElement: HTMLElement, options: CameraRenderingOptions, callbacks: RenderingCallbacks): Promise<RenderedCamera>;
static create(videoConstraints: MediaTrackConstraints): Promise<Camera>;
}

340
node_modules/html5-qrcode/src/camera/core-impl.ts generated vendored Normal file
View File

@@ -0,0 +1,340 @@
/**
* @fileoverview
* Core camera library implementations.
*
* @author mebjas <minhazav@gmail.com>
*/
import {
Camera,
CameraCapabilities,
CameraCapability,
RangeCameraCapability,
CameraRenderingOptions,
RenderedCamera,
RenderingCallbacks,
BooleanCameraCapability
} from "./core";
/** Interface for a range value. */
interface RangeValue {
min: number;
max: number;
step: number;
}
/** Abstract camera capability class. */
abstract class AbstractCameraCapability<T> implements CameraCapability<T> {
protected readonly name: string;
protected readonly track: MediaStreamTrack;
constructor(name: string, track: MediaStreamTrack) {
this.name = name;
this.track = track;
}
public isSupported(): boolean {
// TODO(minhazav): Figure out fallback for getCapabilities()
// in firefox.
// https://developer.mozilla.org/en-US/docs/Web/API/Media_Capture_and_Streams_API/Constraints
if (!this.track.getCapabilities) {
return false;
}
return this.name in this.track.getCapabilities();
}
public apply(value: T): Promise<void> {
let constraint: any = {};
constraint[this.name] = value;
let constraints = { advanced: [ constraint ] };
return this.track.applyConstraints(constraints);
}
public value(): T | null {
let settings: any = this.track.getSettings();
if (this.name in settings) {
let settingValue = settings[this.name];
return settingValue;
}
return null;
}
}
abstract class AbstractRangeCameraCapability extends AbstractCameraCapability<number> {
constructor(name: string, track: MediaStreamTrack) {
super(name, track);
}
public min(): number {
return this.getCapabilities().min;
}
public max(): number {
return this.getCapabilities().max;
}
public step(): number {
return this.getCapabilities().step;
}
public apply(value: number): Promise<void> {
let constraint: any = {};
constraint[this.name] = value;
let constraints = {advanced: [ constraint ]};
return this.track.applyConstraints(constraints);
}
private getCapabilities(): RangeValue {
this.failIfNotSupported();
let capabilities: any = this.track.getCapabilities();
let capability: any = capabilities[this.name];
return {
min: capability.min,
max: capability.max,
step: capability.step,
};
}
private failIfNotSupported() {
if (!this.isSupported()) {
throw new Error(`${this.name} capability not supported`);
}
}
}
/** Zoom feature. */
class ZoomFeatureImpl extends AbstractRangeCameraCapability {
constructor(track: MediaStreamTrack) {
super("zoom", track);
}
}
/** Torch feature. */
class TorchFeatureImpl extends AbstractCameraCapability<boolean> {
constructor(track: MediaStreamTrack) {
super("torch", track);
}
}
/** Implementation of {@link CameraCapabilities}. */
class CameraCapabilitiesImpl implements CameraCapabilities {
private readonly track: MediaStreamTrack;
constructor(track: MediaStreamTrack) {
this.track = track;
}
zoomFeature(): RangeCameraCapability {
return new ZoomFeatureImpl(this.track);
}
torchFeature(): BooleanCameraCapability {
return new TorchFeatureImpl(this.track);
}
}
/** Implementation of {@link RenderedCamera}. */
class RenderedCameraImpl implements RenderedCamera {
private readonly parentElement: HTMLElement;
private readonly mediaStream: MediaStream;
private readonly surface: HTMLVideoElement;
private readonly callbacks: RenderingCallbacks;
private isClosed: boolean = false;
private constructor(
parentElement: HTMLElement,
mediaStream: MediaStream,
callbacks: RenderingCallbacks) {
this.parentElement = parentElement;
this.mediaStream = mediaStream;
this.callbacks = callbacks;
this.surface = this.createVideoElement(this.parentElement.clientWidth);
// Setup
parentElement.append(this.surface);
}
private createVideoElement(width: number): HTMLVideoElement {
const videoElement = document.createElement("video");
videoElement.style.width = `${width}px`;
videoElement.style.display = "block";
videoElement.muted = true;
videoElement.setAttribute("muted", "true");
(<any>videoElement).playsInline = true;
return videoElement;
}
private setupSurface() {
this.surface.onabort = () => {
throw "RenderedCameraImpl video surface onabort() called";
};
this.surface.onerror = () => {
throw "RenderedCameraImpl video surface onerror() called";
};
let onVideoStart = () => {
const videoWidth = this.surface.clientWidth;
const videoHeight = this.surface.clientHeight;
this.callbacks.onRenderSurfaceReady(videoWidth, videoHeight);
this.surface.removeEventListener("playing", onVideoStart);
};
this.surface.addEventListener("playing", onVideoStart);
this.surface.srcObject = this.mediaStream;
this.surface.play();
}
static async create(
parentElement: HTMLElement,
mediaStream: MediaStream,
options: CameraRenderingOptions,
callbacks: RenderingCallbacks)
: Promise<RenderedCamera> {
let renderedCamera = new RenderedCameraImpl(
parentElement, mediaStream, callbacks);
if (options.aspectRatio) {
let aspectRatioConstraint = {
aspectRatio: options.aspectRatio!
};
await renderedCamera.getFirstTrackOrFail().applyConstraints(
aspectRatioConstraint);
}
renderedCamera.setupSurface();
return renderedCamera;
}
private failIfClosed() {
if (this.isClosed) {
throw "The RenderedCamera has already been closed.";
}
}
private getFirstTrackOrFail(): MediaStreamTrack {
this.failIfClosed();
if (this.mediaStream.getVideoTracks().length === 0) {
throw "No video tracks found";
}
return this.mediaStream.getVideoTracks()[0];
}
//#region Public APIs.
public pause(): void {
this.failIfClosed();
this.surface.pause();
}
public resume(onResumeCallback: () => void): void {
this.failIfClosed();
let $this = this;
const onVideoResume = () => {
// Transition after 200ms to avoid the previous canvas frame being
// re-scanned.
setTimeout(onResumeCallback, 200);
$this.surface.removeEventListener("playing", onVideoResume);
};
this.surface.addEventListener("playing", onVideoResume);
this.surface.play();
}
public isPaused(): boolean {
this.failIfClosed();
return this.surface.paused;
}
public getSurface(): HTMLVideoElement {
this.failIfClosed();
return this.surface;
}
public getRunningTrackCapabilities(): MediaTrackCapabilities {
return this.getFirstTrackOrFail().getCapabilities();
}
public getRunningTrackSettings(): MediaTrackSettings {
return this.getFirstTrackOrFail().getSettings();
}
public async applyVideoConstraints(constraints: MediaTrackConstraints)
: Promise<void> {
if ("aspectRatio" in constraints) {
throw "Changing 'aspectRatio' in run-time is not yet supported.";
}
return this.getFirstTrackOrFail().applyConstraints(constraints);
}
public close(): Promise<void> {
if (this.isClosed) {
// Already closed.
return Promise.resolve();
}
let $this = this;
return new Promise((resolve, _) => {
let tracks = $this.mediaStream.getVideoTracks();
const tracksToClose = tracks.length;
var tracksClosed = 0;
$this.mediaStream.getVideoTracks().forEach((videoTrack) => {
$this.mediaStream.removeTrack(videoTrack);
videoTrack.stop();
++tracksClosed;
if (tracksClosed >= tracksToClose) {
$this.isClosed = true;
$this.parentElement.removeChild($this.surface);
resolve();
}
});
});
}
getCapabilities(): CameraCapabilities {
return new CameraCapabilitiesImpl(this.getFirstTrackOrFail());
}
//#endregion
}
/** Default implementation of {@link Camera} interface. */
export class CameraImpl implements Camera {
private readonly mediaStream: MediaStream;
private constructor(mediaStream: MediaStream) {
this.mediaStream = mediaStream;
}
async render(
parentElement: HTMLElement,
options: CameraRenderingOptions,
callbacks: RenderingCallbacks)
: Promise<RenderedCamera> {
return RenderedCameraImpl.create(
parentElement, this.mediaStream, options, callbacks);
}
static async create(videoConstraints: MediaTrackConstraints)
: Promise<Camera> {
if (!navigator.mediaDevices) {
throw "navigator.mediaDevices not supported";
}
let constraints: MediaStreamConstraints = {
audio: false,
video: videoConstraints
};
let mediaStream = await navigator.mediaDevices.getUserMedia(
constraints);
return new CameraImpl(mediaStream);
}
}

41
node_modules/html5-qrcode/src/camera/core.d.ts generated vendored Normal file
View File

@@ -0,0 +1,41 @@
export interface CameraDevice {
id: string;
label: string;
}
export interface CameraCapability<T> {
isSupported(): boolean;
apply(value: T): Promise<void>;
value(): T | null;
}
export interface RangeCameraCapability extends CameraCapability<number> {
min(): number;
max(): number;
step(): number;
}
export interface BooleanCameraCapability extends CameraCapability<boolean> {
}
export interface CameraCapabilities {
zoomFeature(): RangeCameraCapability;
torchFeature(): BooleanCameraCapability;
}
export type OnRenderSurfaceReady = (viewfinderWidth: number, viewfinderHeight: number) => void;
export interface RenderingCallbacks {
onRenderSurfaceReady: OnRenderSurfaceReady;
}
export interface RenderedCamera {
getSurface(): HTMLVideoElement;
pause(): void;
resume(onResumeCallback: () => void): void;
isPaused(): boolean;
close(): Promise<void>;
getRunningTrackCapabilities(): MediaTrackCapabilities;
getRunningTrackSettings(): MediaTrackSettings;
applyVideoConstraints(constraints: MediaTrackConstraints): Promise<void>;
getCapabilities(): CameraCapabilities;
}
export interface CameraRenderingOptions {
aspectRatio?: number;
}
export interface Camera {
render(parentElement: HTMLElement, options: CameraRenderingOptions, callbacks: RenderingCallbacks): Promise<RenderedCamera>;
}

180
node_modules/html5-qrcode/src/camera/core.ts generated vendored Normal file
View File

@@ -0,0 +1,180 @@
/**
* @module
* Core Camera interfaces.
*
* @author mebjas <minhazav@gmail.com>
*/
/** Camera device interface. */
export interface CameraDevice {
id: string;
label: string;
}
//#region Features
/** Generic capability of camera. */
export interface CameraCapability<T> {
/** Returns {@code true} if the capability is supported by the camera. */
isSupported(): boolean;
/** Apply the {@code value} to camera for this capability. */
apply(value: T): Promise<void>;
/** Returns current value of this capability. */
value(): T | null;
}
/** Capability of the camera that has range. */
export interface RangeCameraCapability extends CameraCapability<number> {
/** Min value allowed for this capability. */
min(): number;
/** Max value allowed for this capability. */
max(): number;
/** Steps allowed for this capability. */
step(): number;
}
/** Capability of camera that is boolean in nature. */
export interface BooleanCameraCapability extends CameraCapability<boolean> {}
/** Class exposing different capabilities of camera. */
export interface CameraCapabilities {
/** Zoom capability of the camera. */
zoomFeature(): RangeCameraCapability;
/** Torch capability of the camera. */
torchFeature(): BooleanCameraCapability;
}
//#endregion
/** Type for callback called when camera surface is ready. */
export type OnRenderSurfaceReady
= (viewfinderWidth: number, viewfinderHeight: number) => void;
/** Callbacks around camera rendering. */
export interface RenderingCallbacks {
onRenderSurfaceReady: OnRenderSurfaceReady;
}
/**
* Interface for a rendered camera that is actively showing feed on a surface.
*/
export interface RenderedCamera {
/**
* Returns the video surface.
*
* @throws error if method is called when scanner is not in scanning state.
*/
getSurface(): HTMLVideoElement;
/**
* Pauses the camera feed.
*
* @throws error if method is called when scanner is not in scanning state.
*/
pause(): void;
/**
* Resumes the camera feed, if it's in paused state.
*
* @param onResumeCallback callback that is called when camera resumes.
*
* @throws error if {@link RenderedCamera} instance is already closed.
*/
resume(onResumeCallback: () => void): void;
/**
* Returns {@code true} if the instance is paused.
*
* @throws error if {@link RenderedCamera} instance is already closed.
*/
isPaused(): boolean;
/**
* Closes the instance.
*
* <p> The instance cannot be used after closing.
*/
close(): Promise<void>;
// ---------------------------------------------------------------------------
// Direct Camera Access APIs.
//
// The APIs below are in flavour similar to what Javascript exposes.
// ---------------------------------------------------------------------------
/**
* Returns the capabilities of the running camera stream.
*
* Read more: https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack/getConstraints
*
* @returns the capabilities of a running video track.
* @throws error if {@link RenderedCamera} instance is already closed.
*/
getRunningTrackCapabilities(): MediaTrackCapabilities;
/**
* Returns the object containing the current values of each constrainable
* property of the running video track.
*
* Read more: https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack/getSettings
*
* @returns the supported settings of the running video track.
* @throws error if {@link RenderedCamera} instance is already closed.
*/
getRunningTrackSettings(): MediaTrackSettings;
/**
* Apply a video constraints on running video track from camera.
*
* Important: Changing aspectRatio while scanner is running is not supported
* with this API.
*
* @param {MediaTrackConstraints} specifies a variety of video or camera
* controls as defined in
* https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints
* @returns a Promise which succeeds if the passed constraints are applied,
* fails otherwise.
* @throws error if {@link RenderedCamera} instance is already closed.
*/
applyVideoConstraints(constraints: MediaTrackConstraints): Promise<void>;
/**
* Returns all capabilities of the camera.
*/
getCapabilities(): CameraCapabilities;
}
/** Options for rendering camera feed. */
export interface CameraRenderingOptions {
/**
* Aspect ratio to setup the surface with.
*
* <p> Setting this value doesn't guarantee the exact value to be applied.
*/
aspectRatio?: number;
}
/** Interface for the camera. */
export interface Camera {
/**
* Renders camera to {@link HTMLVideoElement} as a child of
* {@code parentElement}.
*
* @params parentElement Parent HtmlElement to render camera feed into
* @params options rendering options
* @params callbacks callbacks associated with rendering
*
* @returns the {@link RenderedCamera} instance.
*/
render(
parentElement: HTMLElement,
options: CameraRenderingOptions,
callbacks: RenderingCallbacks)
: Promise<RenderedCamera>;
}

6
node_modules/html5-qrcode/src/camera/factories.d.ts generated vendored Normal file
View File

@@ -0,0 +1,6 @@
import { Camera } from "./core";
export declare class CameraFactory {
static failIfNotSupported(): Promise<CameraFactory>;
private constructor();
create(videoConstraints: MediaTrackConstraints): Promise<Camera>;
}

33
node_modules/html5-qrcode/src/camera/factories.ts generated vendored Normal file
View File

@@ -0,0 +1,33 @@
/**
* @fileoverview
* Set of factory implementations around Camera.
*
* @author mebjas <minhazav@gmail.com>
*/
import { Camera } from "./core";
import { CameraImpl } from "./core-impl";
/** Factory class for creating Camera. */
export class CameraFactory {
/**
* Returns {@link CameraFactory} if {@link navigator.mediaDevices} is
* supported else fails.
*/
public static async failIfNotSupported(): Promise<CameraFactory> {
if (!navigator.mediaDevices) {
throw "navigator.mediaDevices not supported";
}
return new CameraFactory();
}
private constructor() { /* No Op. */ }
/** Creates camera instance based on constraints. */
public async create(videoConstraints: MediaTrackConstraints)
: Promise<Camera> {
return CameraImpl.create(videoConstraints);
}
}

View File

@@ -0,0 +1,3 @@
export declare class CameraPermissions {
static hasPermissions(): Promise<boolean>;
}

34
node_modules/html5-qrcode/src/camera/permissions.ts generated vendored Normal file
View File

@@ -0,0 +1,34 @@
/**
* @fileoverview
* Libraries associated with Camera Permissions.
*
* @author mebjas <minhazav@gmail.com>
*/
/**
* Permission management around Camera in javascript.
*
* TODO(mebjas): Migrate camera specific code / logic to this class / library.
*/
export class CameraPermissions {
/**
* Returns {@code true} if the web page already has access to user camera
* permissions.
*/
public static async hasPermissions(): Promise<boolean> {
// TODO(mebjas): Use Permissions Query API, once support is widespread.
// https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query
let devices = await navigator.mediaDevices.enumerateDevices();
for (const device of devices) {
// Hacky way to check if camera permissions are granted. Device
// labels are only set in case user has granted permissions.
if(device.kind === "videoinput" && device.label) {
return true;
}
}
return false;
}
}

8
node_modules/html5-qrcode/src/camera/retriever.d.ts generated vendored Normal file
View File

@@ -0,0 +1,8 @@
import { CameraDevice } from "./core";
export declare class CameraRetriever {
static retrieve(): Promise<Array<CameraDevice>>;
private static rejectWithError;
private static isHttpsOrLocalhost;
private static getCamerasFromMediaDevices;
private static getCamerasFromMediaStreamTrack;
}

93
node_modules/html5-qrcode/src/camera/retriever.ts generated vendored Normal file
View File

@@ -0,0 +1,93 @@
/**
* @fileoverview
* Libraries associated with retrieving cameras.
*
* @author mebjas <minhazav@gmail.com>
*/
import { CameraDevice } from "./core";
import { Html5QrcodeStrings } from "../strings";
/** Class for retrieving cameras on the device. */
export class CameraRetriever {
/** Returns list of {@link CameraDevice} supported by the device. */
public static retrieve(): Promise<Array<CameraDevice>> {
if (navigator.mediaDevices) {
return CameraRetriever.getCamerasFromMediaDevices();
}
// Using deprecated api to support really old browsers.
var mst = <any>MediaStreamTrack;
if (MediaStreamTrack && mst.getSources) {
return CameraRetriever.getCamerasFromMediaStreamTrack();
}
return CameraRetriever.rejectWithError();
}
private static rejectWithError(): Promise<Array<CameraDevice>> {
// This can potentially happen if the page is loaded without SSL.
let errorMessage = Html5QrcodeStrings.unableToQuerySupportedDevices();
if (!CameraRetriever.isHttpsOrLocalhost()) {
errorMessage = Html5QrcodeStrings.insecureContextCameraQueryError();
}
return Promise.reject(errorMessage);
}
private static isHttpsOrLocalhost(): boolean {
if (location.protocol === "https:") {
return true;
}
const host = location.host.split(":")[0];
return host === "127.0.0.1" || host === "localhost";
}
private static async getCamerasFromMediaDevices(): Promise<Array<CameraDevice>> {
// Hacky approach to close any active stream if they are active.
const closeActiveStreams = (stream: MediaStream) => {
const tracks = stream.getVideoTracks();
for (const track of tracks) {
track.enabled = false;
track.stop();
stream.removeTrack(track);
}
};
// This should trigger the permission flow if required.
let mediaStream = await navigator.mediaDevices.getUserMedia(
{ audio: false, video: true });
let devices = await navigator.mediaDevices.enumerateDevices();
let results: Array<CameraDevice> = [];
for (const device of devices) {
if (device.kind === "videoinput") {
results.push({
id: device.deviceId,
label: device.label
});
}
}
closeActiveStreams(mediaStream);
return results;
}
private static getCamerasFromMediaStreamTrack()
: Promise<Array<CameraDevice>> {
return new Promise((resolve, _) => {
const callback = (sourceInfos: Array<any>) => {
const results: Array<CameraDevice> = [];
for (const sourceInfo of sourceInfos) {
if (sourceInfo.kind === "video") {
results.push({
id: sourceInfo.id,
label: sourceInfo.label
});
}
}
resolve(results);
}
var mst = <any>MediaStreamTrack;
mst.getSources(callback);
});
}
}