Skip to content
This repository has been archived by the owner on Oct 19, 2022. It is now read-only.

Commit

Permalink
Import from screen capture and error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Levminer committed Aug 17, 2022
1 parent 95d7389 commit 8164190
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 40 deletions.
10 changes: 6 additions & 4 deletions interface/windows/codes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,14 +249,16 @@ export const chooseImportFile = async () => {
if (filePath !== null) {
const loadedFile = await fs.readTextFile(filePath.toString())
const file: LibAuthmeFile = JSON.parse(loadedFile)
const text = Buffer.from(file.codes, "base64").toString()
const importString = Buffer.from(file.codes, "base64").toString()

saveText = text
saveText = importString

state.importData = text
dialog.message("Codes imported. \n\nYou can edit your codes on the edit page.")

state.importData = importString
setState(state)

generateCodeElements(textConverter(text, 0))
generateCodeElements(textConverter(importString, 0))
}
}

Expand Down
35 changes: 20 additions & 15 deletions interface/windows/import/import.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,26 @@
</div>
</div>

<!-- svelte-ignore a11y-media-has-caption -->
<video class="video" autoplay />
<dialog class="dialog dialog1 overflow-hidden">
<h2>Capture screen</h2>
<h3>Waiting for a QR code...</h3>

<dialog class="dialog dialog0 w-2/3">
<div class="mt-10 flex aspect-video h-60 flex-row space-x-5">
<!-- svelte-ignore a11y-media-has-caption -->
<video class="video rounded-xl bg-white p-1" autoplay />
</div>

<div class="mt-10">
<button class="button stopVideo">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
Stop
</button>
</div>
</dialog>

<dialog class="dialog dialog0">
<h2>Manual entry</h2>
<h3>Please enter the 2FA secret and name!</h3>

Expand Down Expand Up @@ -171,17 +187,6 @@
</dialog>

<script>
import { captureScreen, chooseFile, chooseImages, manualEntry } from "./index"
import { captureScreen, chooseFile, chooseImages, manualEntry, showManualEntry } from "./index"
import Details from "../../components/details.svelte"
const showManualEntry = () => {
const /** @type{LibDialogElement} */ dialog = document.querySelector(".dialog0")
const closeDialog = document.querySelector(".dialog0Close")
closeDialog.addEventListener("click", () => {
dialog.close()
})
dialog.showModal()
}
</script>
109 changes: 88 additions & 21 deletions interface/windows/import/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { getState, setState } from "../../stores/state"
import { totpImageConverter, migrationImageConverter } from "../../libraries/convert"
import { navigate } from "../../libraries/navigate"

/**
* Choose images, then read QR codes
*/
export const chooseImages = async () => {
const filePaths = await dialog.open({ multiple: true, filters: [{ name: "Image file", extensions: ["jpg", "jpeg", "png", "bmp"] }] })

Expand All @@ -22,44 +25,66 @@ export const chooseImages = async () => {
images.push(url)
}

let string = ""
let importString = ""

for (let i = 0; i < images.length; i++) {
const processImages = async () => {
const qr = new QrcodeDecoder()

// decode image
// Decode image
const res = await qr.decodeFromImage(images[i])

if (res === false) {
// no qr code found
// return invoke("error", { invokeMessage: "No QR code found on the picture!\n\nPlease try again with another picture!" })
// No qr code found on the picture
dialog.message(`No QR code found on the #${i + 1} picture! \n\nPlease try again with another picture!`, { type: "error" })
} else if (res.data.startsWith("otpauth://totp/") || res.data.startsWith("otpauth-migration://")) {
if (res.data.startsWith("otpauth://totp/")) {
string += totpImageConverter(res.data)
importString += totpImageConverter(res.data)
} else {
string += migrationImageConverter(res.data)
importString += migrationImageConverter(res.data)
}

if (images.length === i + 1) {
// invoke("info", { invokeMessage: "QR code(s) found!" })
// QR codes found on all images
dialog.message("Codes imported. \n\nYou can edit your codes on the edit page.")

const state = getState()
state.importData += string
state.importData += importString
setState(state)

navigate("codes")
}
} else {
// no qr code found
// return invoke("error", { invokeMessage: "Wrong QR code found on the picture!\n\nPlease try again with another picture!" })
// Wrong QR code found
dialog.message(`Wrong QR code found on the #${i + 1} picture! \n\nPlease try again with another picture!`, { type: "error" })
}
}

processImages()
}
}

/**
* Show manual entry dialog
*/
export const showManualEntry = () => {
const dialog: LibDialogElement = document.querySelector(".dialog0")
const closeDialog = document.querySelector(".dialog0Close")

closeDialog.addEventListener("click", () => {
document.querySelector(".name").value = ""
document.querySelector(".secret").value = ""
document.querySelector(".description").value = ""

dialog.close()
})

dialog.showModal()
}

/**
* Enter a TOTP code manually
*/
export const manualEntry = () => {
const issuer = document.querySelector(".name").value
const secret = document.querySelector(".secret").value
Expand All @@ -77,46 +102,88 @@ export const manualEntry = () => {
name = issuer
}

const string = `\nName: ${name} \nSecret: ${secret} \nIssuer: ${issuer} \nType: OTP_TOTP\n`
const importString = `\nName: ${name} \nSecret: ${secret} \nIssuer: ${issuer} \nType: OTP_TOTP\n`

const state = getState()
state.importData += string
state.importData += importString
setState(state)

navigate("codes")

document.querySelector(".name").value = ""
document.querySelector(".secret").value = ""
document.querySelector(".description").value = ""
}

/**
* Import all codes from an .authme file
*/
export const chooseFile = async () => {
const state = getState()
const filePath = await dialog.open({ filters: [{ name: "Authme file", extensions: ["authme"] }] })

if (filePath !== null) {
const loadedFile = await fs.readTextFile(filePath.toString())
const file: LibAuthmeFile = JSON.parse(loadedFile)
const text = Buffer.from(file.codes, "base64").toString()
const importString = Buffer.from(file.codes, "base64").toString()

state.importData = text
dialog.message("Codes imported. \n\nYou can edit your codes on the edit page.")

state.importData = importString
setState(state)

navigate("codes")
}
}

/**
* Start a video capture, when a QR code detected try to read it
*/
export const captureScreen = async () => {
const dialogElement: LibDialogElement = document.querySelector(".dialog1")
const videoElement: HTMLVideoElement = document.querySelector(".video")

try {
// @ts-ignore
videoElement.srcObject = await navigator.mediaDevices.getDisplayMedia({ audio: false })

let tracks = videoElement.srcObject.getTracks()
const track = videoElement.srcObject.getTracks()[0]

dialogElement.showModal()

document.querySelector(".stopVideo").addEventListener("click", () => {
reader.stop()
track.stop()

dialogElement.close()
})

const reader = new QrcodeDecoder()

console.log(tracks)
const res = await reader.decodeFromVideo(videoElement)

let importString = ""

if (res.data.startsWith("otpauth://totp/") || res.data.startsWith("otpauth-migration://")) {
if (res.data.startsWith("otpauth://totp/")) {
importString += totpImageConverter(res.data)
} else {
importString += migrationImageConverter(res.data)
}

const state = getState()
state.importData += importString
setState(state)

reader.stop()
track.stop()

dialog.message("Codes imported. \n\nYou can edit your codes on the edit page.")

navigate("codes")
} else {
// Wrong QR code found
dialog.message("Wrong QR code found on the picture! \n\nPlease try again with another picture!", { type: "error" })
console.error("Wrong QR code found on the picture:", res)
}
} catch (err) {
console.error(`Error: ${err}`)

dialog.message(`Error occurred during the screen capture: \n\n${err}`, { type: "error" })
}
}

0 comments on commit 8164190

Please sign in to comment.