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:
7
node_modules/html5-qrcode/src/camera/core-impl.d.ts
generated
vendored
Normal file
7
node_modules/html5-qrcode/src/camera/core-impl.d.ts
generated
vendored
Normal 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
340
node_modules/html5-qrcode/src/camera/core-impl.ts
generated
vendored
Normal 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
41
node_modules/html5-qrcode/src/camera/core.d.ts
generated
vendored
Normal 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
180
node_modules/html5-qrcode/src/camera/core.ts
generated
vendored
Normal 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
6
node_modules/html5-qrcode/src/camera/factories.d.ts
generated
vendored
Normal 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
33
node_modules/html5-qrcode/src/camera/factories.ts
generated
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
3
node_modules/html5-qrcode/src/camera/permissions.d.ts
generated
vendored
Normal file
3
node_modules/html5-qrcode/src/camera/permissions.d.ts
generated
vendored
Normal 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
34
node_modules/html5-qrcode/src/camera/permissions.ts
generated
vendored
Normal 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
8
node_modules/html5-qrcode/src/camera/retriever.d.ts
generated
vendored
Normal 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
93
node_modules/html5-qrcode/src/camera/retriever.ts
generated
vendored
Normal 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user