Files
self/app/ios/PhotoLibraryQRScannerViewController.swift
turnoffthiscomputer 2df4dc4619 SELF-725: add iOS qrcode opener and aadhaar screen (#1038)
* add iOS qrcode opener and aadhaar screen

* format

* fix test

* add Image-picker android (#1077)

* add image-picker android

* fix validation

* feat: implement Aadhaar upload success and error screens, enhance AadhaarNavBar with dynamic progress indication

- Added AadhaarUploadedSuccessScreen and AadhaarUploadErrorScreen components for handling upload outcomes.
- Updated AadhaarNavBar to reflect current upload step with dynamic progress bar.
- Integrated new screens into navigation flow for Aadhaar upload process.
- Introduced blue check and warning SVG icons for visual feedback on success and error states.

* feat: generate mock aadhar (#1083)

* feat: generate mock aadhar

* add yarn.lock

* update yarn.lock

* update protocolStore, update types, start modifying provingMachine

* Register mock aadhar (#1093)

* Register mock aadhar

* fix ofac

* temp: generate name

* fix dob

* Add Aadhaar support to ID card component and screens

- Integrated Aadhaar icon and conditional rendering in IdCardLayout.
- Updated AadhaarUploadScreen to process QR codes and store Aadhaar data.
- Modified navigation and button text in AadhaarUploadedSuccessScreen.
- Added mock data generation for Aadhaar in the mobile SDK.
- Updated ManageDocumentsScreen to include Aadhaar document type.
- Enhanced error handling and validation for Aadhaar QR code processing.
- Added utility functions for Aadhaar data extraction and commitment processing.

* aadhaar disclose - wip (#1094)

* fix: timestamp cal of extractQRDataFields

* Feat/aadhar fixes (#1099)

* Fix - android aadhar qr scanner

* fixes

* update text

* yarn nice

* run prettier

* Add mock Aadhaar certificates for development

- Introduced hardcoded Aadhaar test certificates for development purposes.
- Moved Aadhaar mock private and public keys to a dedicated file for better organization.
- Updated the mock ID document generation utility to utilize the new Aadhaar mock certificates.

* prettier write

* add 'add-aadhaar' button (#1100)

* Update .gitleaks.toml to include path for mock certificates in the common/dist directory

* yarn nice

* Enhance Aadhaar error handling with specific error types

- Updated the AadhaarUploadErrorScreen to display different messages based on the error type (general or expired).
- Modified the AadhaarUploadScreen to pass the appropriate error type when navigating to the error screen.
- Set initial parameters for the home screen to include a default error type.

* Update passport handling in proving machine to support Aadhaar document category

- Modified the handling of country code in the useProvingStore to return 'IND' for Aadhaar documents.
- Ensured that the country code is only fetched from passport metadata for non-Aadhaar documents.

* tweak layout, text, change email to support, hide help button

* fix ci, remove aadhaar logging, add aadhaar events

* remove unused aadhaar tracking events

* update globs

* fix gitguardian config

* don't track id

---------

Co-authored-by: Justin Hernandez <justin.hernandez@self.xyz>
Co-authored-by: Seshanth.S🐺 <35675963+seshanthS@users.noreply.github.com>
Co-authored-by: vishal <vishalkoolkarni0045@gmail.com>
2025-09-19 17:36:01 -07:00

153 lines
4.4 KiB
Swift

//
// PhotoLibraryQRScannerViewController.swift
// Self
//
// Created by Rémi Colin on 09/09/2025.
//
// SPDX-License-Identifier: BUSL-1.1; Copyright (c) 2025 Social Connect Labs, Inc.; Licensed under BUSL-1.1 (see LICENSE); Apache-2.0 from 2029-06-11
//
// PhotoLibraryQRScannerViewController.swift
// OpenPassport
//
// Created by AI Assistant on 01/03/2025.
//
import Foundation
import UIKit
import CoreImage
import Photos
class PhotoLibraryQRScannerViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var completionHandler: ((String) -> Void)?
var errorHandler: ((Error) -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
checkPhotoLibraryPermissionAndPresentPicker()
}
private func checkPhotoLibraryPermissionAndPresentPicker() {
let status = PHPhotoLibrary.authorizationStatus()
switch status {
case .authorized, .limited:
presentImagePicker()
case .notDetermined:
PHPhotoLibrary.requestAuthorization { [weak self] status in
DispatchQueue.main.async {
if status == .authorized || status == .limited {
self?.presentImagePicker()
} else {
self?.handlePermissionDenied()
}
}
}
case .denied, .restricted:
handlePermissionDenied()
@unknown default:
handlePermissionDenied()
}
}
private func presentImagePicker() {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.mediaTypes = ["public.image"]
present(imagePicker, animated: true, completion: nil)
}
private func handlePermissionDenied() {
let error = NSError(
domain: "QRScannerError",
code: 1001,
userInfo: [NSLocalizedDescriptionKey: "Photo library access is required to scan QR codes from photos. Please enable access in Settings."]
)
errorHandler?(error)
dismiss(animated: true, completion: nil)
}
// MARK: - UIImagePickerControllerDelegate
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
picker.dismiss(animated: true) { [weak self] in
guard let self = self else { return }
if let selectedImage = info[.originalImage] as? UIImage {
self.detectQRCode(in: selectedImage)
} else {
let error = NSError(
domain: "QRScannerError",
code: 1002,
userInfo: [NSLocalizedDescriptionKey: "Failed to load the selected image."]
)
self.errorHandler?(error)
self.dismiss(animated: true, completion: nil)
}
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true) { [weak self] in
let error = NSError(
domain: "QRScannerError",
code: 1003,
userInfo: [NSLocalizedDescriptionKey: "User cancelled photo selection."]
)
self?.errorHandler?(error)
self?.dismiss(animated: true, completion: nil)
}
}
// MARK: - QR Code Detection
private func detectQRCode(in image: UIImage) {
guard let ciImage = CIImage(image: image) else {
let error = NSError(
domain: "QRScannerError",
code: 1004,
userInfo: [NSLocalizedDescriptionKey: "Failed to process the selected image."]
)
errorHandler?(error)
dismiss(animated: true, completion: nil)
return
}
let detector = CIDetector(
ofType: CIDetectorTypeQRCode,
context: nil,
options: [CIDetectorAccuracy: CIDetectorAccuracyHigh]
)
guard let detector = detector else {
let error = NSError(
domain: "QRScannerError",
code: 1005,
userInfo: [NSLocalizedDescriptionKey: "Failed to initialize QR code detector."]
)
errorHandler?(error)
dismiss(animated: true, completion: nil)
return
}
let features = detector.features(in: ciImage) as? [CIQRCodeFeature] ?? []
if let firstQRCode = features.first, let qrCodeString = firstQRCode.messageString {
completionHandler?(qrCodeString)
dismiss(animated: true, completion: nil)
} else {
let error = NSError(
domain: "QRScannerError",
code: 1006,
userInfo: [NSLocalizedDescriptionKey: "No QR code found in the selected image. Please try with a different image."]
)
errorHandler?(error)
dismiss(animated: true, completion: nil)
}
}
}