Browse Source

refactor: Improve QR code scanning and JWT handling

- Enhanced JWT extraction and validation in getContactJwtFromJwtUrl
- Added robust error handling in decodeEndorserJwt with fallback manual decoding
- Improved QR code scanning with better type safety and error handling
- Refactored ContactQRScanShowView component for better maintainability
- Added comprehensive logging throughout the scanning process
- Improved cleanup handling for camera and listeners
- Added proper TypeScript interfaces for scan results
- Enhanced error messages for better user feedback

Security:
- Added validation for JWT format and required fields
- Improved error handling for malformed JWTs
- Added input validation for QR code URLs
- Redacted sensitive data in logs

BREAKING CHANGE: JWT handling now supports multiple URL patterns and has stricter validation
qrcode-capacitor
Matthew Raymer 3 months ago
parent
commit
b79cccc591
  1. 8
      android/gradle.properties
  2. 406
      package-lock.json
  3. 48
      src/libs/crypto/index.ts
  4. 31
      src/libs/crypto/vc/index.ts
  5. 288
      src/views/ContactQRScanShowView.vue

8
android/gradle.properties

@ -9,7 +9,7 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -Djdk.io.File.enableADS=true -Dsun.net.inetaddr.ttl=0 -Dsun.net.inetaddr.negative.ttl=0 -Dsun.net.client.defaultConnectTimeout=10000 -Dsun.net.client.defaultReadTimeout=10000
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
@ -20,4 +20,8 @@ org.gradle.jvmargs=-Xmx1536m
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
android.suppressUnsupportedCompileSdk=34
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Use DNS servers that can resolve Google's Maven repository
systemProp.sun.net.spi.nameservice.nameservers=8.8.8.8,8.8.4.4
systemProp.sun.net.spi.nameservice.provider.1=dns,sun

406
package-lock.json

@ -4562,9 +4562,9 @@
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz",
"integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==",
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.0.tgz",
"integrity": "sha512-WhCn7Z7TauhBtmzhvKpoQs0Wwb/kBcy4CwpuI0/eEIr2Lx2auxmulAzLr91wVZJaz47iUZdkXOK7WlAfxGKCnA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -5263,9 +5263,9 @@
}
},
"node_modules/@expo/cli": {
"version": "0.22.24",
"resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.22.24.tgz",
"integrity": "sha512-lhdenxBC8/x/vL39j79eXE09mOaqNNLmiSDdY/PblnI+UNzGgsQ48hBTYa/MQhd0ioXXVKurZL2941dLKwcxJw==",
"version": "0.22.26",
"resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.22.26.tgz",
"integrity": "sha512-I689wc8Fn/AX7aUGiwrh3HnssiORMJtR2fpksX+JIe8Cj/EDleblYMSwRPd0025wrwOV9UN1KM/RuEt/QjCS3Q==",
"license": "MIT",
"optional": true,
"peer": true,
@ -5283,7 +5283,7 @@
"@expo/osascript": "^2.1.6",
"@expo/package-manager": "^1.7.2",
"@expo/plist": "^0.2.2",
"@expo/prebuild-config": "^8.0.31",
"@expo/prebuild-config": "~8.2.0",
"@expo/rudder-sdk-node": "^1.1.1",
"@expo/spawn-async": "^1.7.2",
"@expo/ws-tunnel": "^1.0.1",
@ -6049,6 +6049,20 @@
"getenv": "^1.0.0"
}
},
"node_modules/@expo/env/node_modules/dotenv": {
"version": "16.4.7",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
"integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
"license": "BSD-2-Clause",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/@expo/fingerprint": {
"version": "0.11.11",
"resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.11.11.tgz",
@ -6652,9 +6666,9 @@
}
},
"node_modules/@expo/prebuild-config": {
"version": "8.0.31",
"resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-8.0.31.tgz",
"integrity": "sha512-YTuS5ic9KolD/WA3GqgLcZytHQU1dpitlZ/cbDq8ZqkY+1ae5YWX+GkYEZf2VyECPaWnHYuDGddaTQVw5miTRg==",
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-8.2.0.tgz",
"integrity": "sha512-CxiPpd980s0jyxi7eyN3i/7YKu3XL+8qPjBZUCYtc0+axpGweqIkq2CslyLSKHyqVyH/zlPkbVgWdyiYavFS5Q==",
"license": "MIT",
"optional": true,
"peer": true,
@ -7723,12 +7737,12 @@
}
},
"node_modules/@noble/curves": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz",
"integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==",
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz",
"integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==",
"license": "MIT",
"dependencies": {
"@noble/hashes": "1.7.1"
"@noble/hashes": "1.7.2"
},
"engines": {
"node": "^14.21.3 || >=16"
@ -7738,9 +7752,9 @@
}
},
"node_modules/@noble/ed25519": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz",
"integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==",
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.4.tgz",
"integrity": "sha512-gZNqhA4H2Ev+8nlvz/L7n3GQwOU86kYHYG6OWb3ekRbqHXmIYJyzw3DbpmaAfhlEsgbNPJUIq0esvYRl5dBVkg==",
"funding": [
{
"type": "individual",
@ -7751,9 +7765,9 @@
"optional": true
},
"node_modules/@noble/hashes": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz",
"integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==",
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz",
"integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==",
"license": "MIT",
"engines": {
"node": "^14.21.3 || >=16"
@ -7988,16 +8002,16 @@
}
},
"node_modules/@pkgr/core": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.1.tgz",
"integrity": "sha512-VzgHzGblFmUeBmmrk55zPyrQIArQN4vujc9shWytaPdB3P7qhi0cpaiKIr7tlCmFv2lYUwnLospIqjL9ZSAhhg==",
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.4.tgz",
"integrity": "sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/unts"
"url": "https://opencollective.com/pkgr"
}
},
"node_modules/@playwright/test": {
@ -8059,9 +8073,9 @@
}
},
"node_modules/@react-native/assets-registry": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.79.0.tgz",
"integrity": "sha512-Rwvpu3A05lM1HVlX4klH4UR52JbQPDKc8gi2mst2REZL1KeVgJRJxPPw8d8euVlYcq/s8XI1Ol827JaRtSZBTA==",
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.79.1.tgz",
"integrity": "sha512-q5BwZtL0YbaJRgofl8qrD9BNdGJkecTJNYG8VFOVQYXPTBa3ZSooip1aj0wrjoa0HloKx/Hmx5UMvuhfEsjn8A==",
"license": "MIT",
"optional": true,
"peer": true,
@ -8169,14 +8183,14 @@
}
},
"node_modules/@react-native/community-cli-plugin": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.79.0.tgz",
"integrity": "sha512-pl+aSXxGj3ug80FpMDrArjxUbJWY2ibWiSP3MLKX+Xk7An2GUmFFjCzNVSbs0jzWv8814EG2oI60/GH2RXwE4g==",
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.79.1.tgz",
"integrity": "sha512-hqCMQrMRi19G7yxEsYwV9A0MHB6Hri7B5dytRD7kU5vtz0Lzg1fZYYvmS0x9OdWJWPntmHA8xiijwM+4cT8cpQ==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@react-native/dev-middleware": "0.79.0",
"@react-native/dev-middleware": "0.79.1",
"chalk": "^4.0.0",
"debug": "^2.2.0",
"invariant": "^2.2.4",
@ -8198,9 +8212,9 @@
}
},
"node_modules/@react-native/community-cli-plugin/node_modules/@react-native/debugger-frontend": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.79.0.tgz",
"integrity": "sha512-chwKEWAmQMkOKZWwBra+utquuJ/2uFqh+ZgZbJfNX+U0YsBx6AQ3dVbfAaXW3bSLYEJyf9Wb3Opsal4fmcD9Ww==",
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.79.1.tgz",
"integrity": "sha512-IgbQM/djzBhkkjzIT/b36zwkc4UMxZLTKgRVJrSEjuwtOPmgfh/1F5m3OUitbMd4/e06VgN0vPLyBzToj1kiwA==",
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
@ -8209,15 +8223,15 @@
}
},
"node_modules/@react-native/community-cli-plugin/node_modules/@react-native/dev-middleware": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.79.0.tgz",
"integrity": "sha512-8Mh5L8zJXis2qhgkfXnWMbSmcvb07wrbxQe8KIgIO7C1rS97idg7BBtoPEtmARsaQgmbSGu/wdE7UWFkGYp0OQ==",
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.79.1.tgz",
"integrity": "sha512-xegUHwi6h8wOLIl/9ImZoIVVwzecE+ENGTELIrD2PsseBbtdRMKzZ8A1LTBjPPt3IjHPH6103JcSPwgepP6zFA==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@isaacs/ttlcache": "^1.4.1",
"@react-native/debugger-frontend": "0.79.0",
"@react-native/debugger-frontend": "0.79.1",
"chrome-launcher": "^0.15.2",
"chromium-edge-launcher": "^0.2.0",
"connect": "^3.6.5",
@ -8365,9 +8379,9 @@
}
},
"node_modules/@react-native/gradle-plugin": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.79.0.tgz",
"integrity": "sha512-c+/qKnmTx3kf8xZesp2BkZ9pAQVSnEPZziQUwviSJaq9jm8tKb/B8fyGG8yIuw/ZTKyGprD+ByzUSzJmCpC/Ow==",
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.79.1.tgz",
"integrity": "sha512-vfoNcOBig/+R7g3eqHkBSbSVkk0NMPzyXE5QY0V+/0flRa3kDZUHP2fr8ygoY/4rxbi05wPME2/dTEuoYcpnjg==",
"license": "MIT",
"optional": true,
"peer": true,
@ -8376,9 +8390,9 @@
}
},
"node_modules/@react-native/js-polyfills": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.79.0.tgz",
"integrity": "sha512-+8lk/zP90JC9xZBGhI8TPqqR1Y5dYXwXvfhXygr/LlHoo+H8TeQxcPrXWdT+PWOJl6Gf7dbCOGh9Std8J7CSQA==",
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.79.1.tgz",
"integrity": "sha512-P8j11kdD+ehL5jqHSCM1BOl4SnJ+3rvGPpsagAqyngU6WSausISO7YFufltrWA7kdpHdnAL2HfJJ62szTRGShw==",
"license": "MIT",
"optional": true,
"peer": true,
@ -8395,9 +8409,9 @@
"peer": true
},
"node_modules/@react-native/virtualized-lists": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.79.0.tgz",
"integrity": "sha512-tCT1sHSI1O5KSclDwNfnkLTLe3cgiyYWjIlmNxWJHqhCCz017HGOS/oH0zs0ZgxYwN7xCzTkqY330XMDo+yj2g==",
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.79.1.tgz",
"integrity": "sha512-v1KeqJeVJXjc2mewjKQYSay7D7+VSacxryejuuVXlPE9E9wVbzMPCfPjbIS8C9nMC7a4rsRFilX7RVKYkeZaGg==",
"license": "MIT",
"optional": true,
"peer": true,
@ -8504,9 +8518,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.39.0.tgz",
"integrity": "sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz",
"integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==",
"cpu": [
"arm"
],
@ -8518,9 +8532,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.39.0.tgz",
"integrity": "sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz",
"integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==",
"cpu": [
"arm64"
],
@ -8532,9 +8546,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.39.0.tgz",
"integrity": "sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz",
"integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==",
"cpu": [
"arm64"
],
@ -8546,9 +8560,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.39.0.tgz",
"integrity": "sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz",
"integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==",
"cpu": [
"x64"
],
@ -8560,9 +8574,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.39.0.tgz",
"integrity": "sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz",
"integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==",
"cpu": [
"arm64"
],
@ -8574,9 +8588,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.39.0.tgz",
"integrity": "sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz",
"integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==",
"cpu": [
"x64"
],
@ -8588,9 +8602,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.39.0.tgz",
"integrity": "sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz",
"integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==",
"cpu": [
"arm"
],
@ -8602,9 +8616,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.39.0.tgz",
"integrity": "sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz",
"integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==",
"cpu": [
"arm"
],
@ -8616,9 +8630,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.39.0.tgz",
"integrity": "sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz",
"integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==",
"cpu": [
"arm64"
],
@ -8630,9 +8644,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.39.0.tgz",
"integrity": "sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz",
"integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==",
"cpu": [
"arm64"
],
@ -8644,9 +8658,9 @@
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.39.0.tgz",
"integrity": "sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz",
"integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==",
"cpu": [
"loong64"
],
@ -8658,9 +8672,9 @@
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.39.0.tgz",
"integrity": "sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz",
"integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==",
"cpu": [
"ppc64"
],
@ -8672,9 +8686,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.39.0.tgz",
"integrity": "sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz",
"integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==",
"cpu": [
"riscv64"
],
@ -8686,9 +8700,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.39.0.tgz",
"integrity": "sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz",
"integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==",
"cpu": [
"riscv64"
],
@ -8700,9 +8714,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.39.0.tgz",
"integrity": "sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz",
"integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==",
"cpu": [
"s390x"
],
@ -8714,9 +8728,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.39.0.tgz",
"integrity": "sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz",
"integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==",
"cpu": [
"x64"
],
@ -8728,9 +8742,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.39.0.tgz",
"integrity": "sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz",
"integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==",
"cpu": [
"x64"
],
@ -8742,9 +8756,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.39.0.tgz",
"integrity": "sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz",
"integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==",
"cpu": [
"arm64"
],
@ -8756,9 +8770,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.39.0.tgz",
"integrity": "sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz",
"integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==",
"cpu": [
"ia32"
],
@ -8770,9 +8784,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.39.0.tgz",
"integrity": "sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz",
"integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==",
"cpu": [
"x64"
],
@ -9982,9 +9996,9 @@
"license": "MIT"
},
"node_modules/@types/webxr": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.21.tgz",
"integrity": "sha512-geZIAtLzjGmgY2JUi6VxXdCrTb99A7yP49lxLr2Nm/uIK0PkkxcEi4OGhoGDO4pxCf3JwGz2GiJL2Ej4K2bKaA==",
"version": "0.5.22",
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz",
"integrity": "sha512-Vr6Stjv5jPRqH690f5I5GLjVk8GSsoQSYJ2FVd/3jJF7KaqfwPi3ehfBS96mlQ2kPCwZaX6U0rG2+NGHBKkA/A==",
"dev": true,
"license": "MIT"
},
@ -10532,9 +10546,9 @@
}
},
"node_modules/@veramo/did-provider-peer/node_modules/did-jwt": {
"version": "8.0.9",
"resolved": "https://registry.npmjs.org/did-jwt/-/did-jwt-8.0.9.tgz",
"integrity": "sha512-Tc2wdkGwAyqiL1oYZvdIJ4k/LcrUpJIcXEQNb/yyegY9/CPeeXEbwsgg8BDAaoYdaDFknyFolLZb+Sp9uU1U5w==",
"version": "8.0.11",
"resolved": "https://registry.npmjs.org/did-jwt/-/did-jwt-8.0.11.tgz",
"integrity": "sha512-Uz2BRDr/PoLyXXPLSziNVVvFc3XgZCnB2bDla+5/FGgbdbWDzVqOyTUMxSNbUlsmrmHeZMH3KnaybW+PfplGNA==",
"license": "Apache-2.0",
"dependencies": {
"@noble/ciphers": "^1.0.0",
@ -10549,9 +10563,9 @@
}
},
"node_modules/@veramo/did-provider-peer/node_modules/did-jwt-vc": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/did-jwt-vc/-/did-jwt-vc-4.0.7.tgz",
"integrity": "sha512-8S/LtonGXOyFgzJAdVM7Vu6+Eryj5YR4fdaHMtC0pmXZXhJPXF4Xtrin4ZElTMSJUQsEIfR6HF5hziOJfHQ4fQ==",
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/did-jwt-vc/-/did-jwt-vc-4.0.9.tgz",
"integrity": "sha512-kDpVLZFf2nO/taasDR3Hw/ow56pZFZzI677urWhAELach+3Q6lijQhBMNnuAyjUVWr1NiHOnBp1QHzBBf8zN7w==",
"license": "ISC",
"dependencies": {
"did-jwt": "^8.0.0",
@ -13001,9 +13015,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001712",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001712.tgz",
"integrity": "sha512-MBqPpGYYdQ7/hfKiet9SCI+nmN5/hp4ZzveOJubl5DTAMa5oggjAuoi0Z4onBpKPFI2ePGnQuQIzF3VxDjDJig==",
"version": "1.0.30001714",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001714.tgz",
"integrity": "sha512-mtgapdwDLSSBnCI3JokHM7oEQBLxiJKVRtg10AxM1AyeiKcM96f0Mkbqeq+1AbiCtvMcHRulAAEMu693JrSWqg==",
"devOptional": true,
"funding": [
{
@ -15184,9 +15198,9 @@
}
},
"node_modules/dotenv": {
"version": "16.4.7",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
"integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
"version": "16.5.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz",
"integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
@ -15270,9 +15284,9 @@
}
},
"node_modules/electron": {
"version": "33.4.8",
"resolved": "https://registry.npmjs.org/electron/-/electron-33.4.8.tgz",
"integrity": "sha512-dy/92HufGG66PslDMlXuK6uhO+70tgiZ4esReTZgDcZ0E67jCJ7S4/et4yZSEjXiT7IyjZTf72QwQbTpANxW4g==",
"version": "33.4.9",
"resolved": "https://registry.npmjs.org/electron/-/electron-33.4.9.tgz",
"integrity": "sha512-XJQFXPOzHtUd7WtPlRhV6TD6QTwHLMjl+yZVD5krtPQ59KxJcZuMDJZJVPdLLlb5uSNo4iWTc204Lt7i2dFp5Q==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@ -15401,9 +15415,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.5.134",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.134.tgz",
"integrity": "sha512-zSwzrLg3jNP3bwsLqWHmS5z2nIOQ5ngMnfMZOWWtXnqqQkPVyOipxK98w+1beLw1TB+EImPNcG8wVP/cLVs2Og==",
"version": "1.5.137",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.137.tgz",
"integrity": "sha512-/QSJaU2JyIuTbbABAo/crOs+SuAZLS+fVVS10PVrIT9hrRkmZl8Hb0xPSkKRUUWHQtYzXHpQUW3Dy5hwMzGZkA==",
"devOptional": true,
"license": "ISC"
},
@ -16210,9 +16224,9 @@
"license": "MIT"
},
"node_modules/ethr-did": {
"version": "3.0.26",
"resolved": "https://registry.npmjs.org/ethr-did/-/ethr-did-3.0.26.tgz",
"integrity": "sha512-iWThKxmkryrrlPrYGy1BJYSgwYY272trZZvBLMKavvnSibMDX3aoAtudjtKcsgkyJ4540TdsztpqPtzny9wNrg==",
"version": "3.0.28",
"resolved": "https://registry.npmjs.org/ethr-did/-/ethr-did-3.0.28.tgz",
"integrity": "sha512-kCfsD9kgM6JH3v8nWPlqOQNMvKwni4u9lwYUd+iNqViZT/17Zu1NcnTyJnKiEUQ9QdIOA10FUe2F9qcTkcDWQw==",
"license": "Apache-2.0",
"dependencies": {
"did-jwt": "^8.0.0",
@ -16244,9 +16258,9 @@
}
},
"node_modules/ethr-did/node_modules/did-jwt": {
"version": "8.0.9",
"resolved": "https://registry.npmjs.org/did-jwt/-/did-jwt-8.0.9.tgz",
"integrity": "sha512-Tc2wdkGwAyqiL1oYZvdIJ4k/LcrUpJIcXEQNb/yyegY9/CPeeXEbwsgg8BDAaoYdaDFknyFolLZb+Sp9uU1U5w==",
"version": "8.0.11",
"resolved": "https://registry.npmjs.org/did-jwt/-/did-jwt-8.0.11.tgz",
"integrity": "sha512-Uz2BRDr/PoLyXXPLSziNVVvFc3XgZCnB2bDla+5/FGgbdbWDzVqOyTUMxSNbUlsmrmHeZMH3KnaybW+PfplGNA==",
"license": "Apache-2.0",
"dependencies": {
"@noble/ciphers": "^1.0.0",
@ -16434,15 +16448,15 @@
}
},
"node_modules/expo": {
"version": "52.0.44",
"resolved": "https://registry.npmjs.org/expo/-/expo-52.0.44.tgz",
"integrity": "sha512-qj3+MWxmqLyBaYQ8jDOvVLEgSqNplH3cf+nDhxCo4C1cpTPD1u/HGh1foibtaeuCYLHsE5km1lrcOpRbFJ4luQ==",
"version": "52.0.46",
"resolved": "https://registry.npmjs.org/expo/-/expo-52.0.46.tgz",
"integrity": "sha512-JG89IVZLp7DWzgeiQb+0N43kWOF1DUm3esBvAS9cPFWZsM9x8nDXgbvtREcycDPA6E+yJsSC+086CigeUY6sVA==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/runtime": "^7.20.0",
"@expo/cli": "0.22.24",
"@expo/cli": "0.22.26",
"@expo/config": "~10.0.11",
"@expo/config-plugins": "~9.0.17",
"@expo/fingerprint": "0.11.11",
@ -17131,9 +17145,9 @@
"peer": true
},
"node_modules/flow-parser": {
"version": "0.266.1",
"resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.266.1.tgz",
"integrity": "sha512-dON6h+yO7FGa/FO5NQCZuZHN0o3I23Ev6VYOJf9d8LpdrArHPt39wE++LLmueNV/hNY5hgWGIIrgnrDkRcXkPg==",
"version": "0.267.0",
"resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.267.0.tgz",
"integrity": "sha512-eBgyFHiT/CHevT225CVQbwnAwRKLjqgtkkpDBMvNGV2C/Tz8x4Zr9FZeWed/cSWhRTiUhH7MXpIWSHkrzvaqdA==",
"license": "MIT",
"optional": true,
"peer": true,
@ -19874,9 +19888,9 @@
"license": "Apache-2.0"
},
"node_modules/katex": {
"version": "0.16.21",
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.21.tgz",
"integrity": "sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A==",
"version": "0.16.22",
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz",
"integrity": "sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==",
"dev": true,
"funding": [
"https://opencollective.com/katex",
@ -21183,9 +21197,9 @@
}
},
"node_modules/marky": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz",
"integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz",
"integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==",
"license": "Apache-2.0",
"optional": true,
"peer": true
@ -23467,9 +23481,9 @@
}
},
"node_modules/npm-check-updates": {
"version": "17.1.16",
"resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-17.1.16.tgz",
"integrity": "sha512-9nohkfjLRzLfsLVGbO34eXBejvrOOTuw5tvNammH73KEFG5XlFoi3G2TgjTExHtnrKWCbZ+mTT+dbNeSjASIPw==",
"version": "17.1.18",
"resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-17.1.18.tgz",
"integrity": "sha512-bkUy2g4v1i+3FeUf5fXMLbxmV95eG4/sS7lYE32GrUeVgQRfQEk39gpskksFunyaxQgTIdrvYbnuNbO/pSUSqw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@ -25168,21 +25182,21 @@
"peer": true
},
"node_modules/react-native": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.79.0.tgz",
"integrity": "sha512-fLG/zl/YF30TWTmp2bbo3flHSFGe4WTyVkb7/wJnMEC39jjXVSCxfDtvSUVavhCc03fA/RTkWWvlmg7NEJk7Vg==",
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.79.1.tgz",
"integrity": "sha512-MZQFEKyKPjqvyjuMUvH02elnmRQFzbS0yf46YOe9ktJWTZGwklsbJkRgaXJx9KA3SK6v1/QXVeCqZmrzho+1qw==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/create-cache-key-function": "^29.7.0",
"@react-native/assets-registry": "0.79.0",
"@react-native/codegen": "0.79.0",
"@react-native/community-cli-plugin": "0.79.0",
"@react-native/gradle-plugin": "0.79.0",
"@react-native/js-polyfills": "0.79.0",
"@react-native/normalize-colors": "0.79.0",
"@react-native/virtualized-lists": "0.79.0",
"@react-native/assets-registry": "0.79.1",
"@react-native/codegen": "0.79.1",
"@react-native/community-cli-plugin": "0.79.1",
"@react-native/gradle-plugin": "0.79.1",
"@react-native/js-polyfills": "0.79.1",
"@react-native/normalize-colors": "0.79.1",
"@react-native/virtualized-lists": "0.79.1",
"abort-controller": "^3.0.0",
"anser": "^1.4.9",
"ansi-regex": "^5.0.0",
@ -25242,9 +25256,9 @@
}
},
"node_modules/react-native/node_modules/@react-native/codegen": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.79.0.tgz",
"integrity": "sha512-D8bFlD0HH9SMUI00svdg64hEvLbu4ETeWQDlmEP8WmNbuILjwoLFqbnBmlGn69Tot0DM1PuBd1l1ooIzs8sU7w==",
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.79.1.tgz",
"integrity": "sha512-cTVXfCICkmUU6UvUpnLP4BE82O14JRuVz42cg/A19oasTaZmzHl0+uIDzt2cZEbt/N2sJ/EZnZL61qqpwbNXWQ==",
"license": "MIT",
"optional": true,
"peer": true,
@ -25263,9 +25277,9 @@
}
},
"node_modules/react-native/node_modules/@react-native/normalize-colors": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.79.0.tgz",
"integrity": "sha512-RmM7Dgb69a4qwdguKR+8MhT0u1IAKa/s0uy8/7JP9b/fm8zjUV9HctMgRgIpZTOELsowEyQodyTnhHQf4HPX0A==",
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.79.1.tgz",
"integrity": "sha512-Fj12xKyihZhrFH45ruqECd2JVx9lyYe+dyxO7MYgkqY6UENsSS3JKcfzjSNBZLW7NXts6JkbaqLQPwaHmPF7QA==",
"license": "MIT",
"optional": true,
"peer": true
@ -26379,9 +26393,9 @@
}
},
"node_modules/rollup": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.39.0.tgz",
"integrity": "sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g==",
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz",
"integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -26395,26 +26409,26 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.39.0",
"@rollup/rollup-android-arm64": "4.39.0",
"@rollup/rollup-darwin-arm64": "4.39.0",
"@rollup/rollup-darwin-x64": "4.39.0",
"@rollup/rollup-freebsd-arm64": "4.39.0",
"@rollup/rollup-freebsd-x64": "4.39.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.39.0",
"@rollup/rollup-linux-arm-musleabihf": "4.39.0",
"@rollup/rollup-linux-arm64-gnu": "4.39.0",
"@rollup/rollup-linux-arm64-musl": "4.39.0",
"@rollup/rollup-linux-loongarch64-gnu": "4.39.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.39.0",
"@rollup/rollup-linux-riscv64-gnu": "4.39.0",
"@rollup/rollup-linux-riscv64-musl": "4.39.0",
"@rollup/rollup-linux-s390x-gnu": "4.39.0",
"@rollup/rollup-linux-x64-gnu": "4.39.0",
"@rollup/rollup-linux-x64-musl": "4.39.0",
"@rollup/rollup-win32-arm64-msvc": "4.39.0",
"@rollup/rollup-win32-ia32-msvc": "4.39.0",
"@rollup/rollup-win32-x64-msvc": "4.39.0",
"@rollup/rollup-android-arm-eabi": "4.40.0",
"@rollup/rollup-android-arm64": "4.40.0",
"@rollup/rollup-darwin-arm64": "4.40.0",
"@rollup/rollup-darwin-x64": "4.40.0",
"@rollup/rollup-freebsd-arm64": "4.40.0",
"@rollup/rollup-freebsd-x64": "4.40.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.40.0",
"@rollup/rollup-linux-arm-musleabihf": "4.40.0",
"@rollup/rollup-linux-arm64-gnu": "4.40.0",
"@rollup/rollup-linux-arm64-musl": "4.40.0",
"@rollup/rollup-linux-loongarch64-gnu": "4.40.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.40.0",
"@rollup/rollup-linux-riscv64-gnu": "4.40.0",
"@rollup/rollup-linux-riscv64-musl": "4.40.0",
"@rollup/rollup-linux-s390x-gnu": "4.40.0",
"@rollup/rollup-linux-x64-gnu": "4.40.0",
"@rollup/rollup-linux-x64-musl": "4.40.0",
"@rollup/rollup-win32-arm64-msvc": "4.40.0",
"@rollup/rollup-win32-ia32-msvc": "4.40.0",
"@rollup/rollup-win32-x64-msvc": "4.40.0",
"fsevents": "~2.3.2"
}
},
@ -28436,13 +28450,13 @@
}
},
"node_modules/synckit": {
"version": "0.11.3",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.3.tgz",
"integrity": "sha512-szhWDqNNI9etJUvbZ1/cx1StnZx8yMmFxme48SwR4dty4ioSY50KEZlpv0qAfgc1fpRzuh9hBXEzoCpJ779dLg==",
"version": "0.11.4",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.4.tgz",
"integrity": "sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@pkgr/core": "^0.2.1",
"@pkgr/core": "^0.2.3",
"tslib": "^2.8.1"
},
"engines": {
@ -29873,9 +29887,9 @@
}
},
"node_modules/vite": {
"version": "5.4.17",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.17.tgz",
"integrity": "sha512-5+VqZryDj4wgCs55o9Lp+p8GE78TLVg0lasCH5xFZ4jacZjtqZa6JUw9/p0WeAojaOfncSM6v77InkFPGnvPvg==",
"version": "5.4.18",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.18.tgz",
"integrity": "sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA==",
"dev": true,
"license": "MIT",
"dependencies": {

48
src/libs/crypto/index.ts

@ -104,33 +104,41 @@ export const accessToken = async (did?: string) => {
};
/**
@return payload of JWT pulled out of any recognized URL path (if any)
* Extract JWT from various URL formats
* @param jwtUrlText URL or text containing a JWT
* @return JWT string if found, original text otherwise
*/
export const getContactJwtFromJwtUrl = (jwtUrlText: string) => {
let jwtText = jwtUrlText;
const appImportConfirmUrlLoc = jwtText.indexOf(
// Handle various URL patterns
const URL_PATTERNS = [
"/contact/confirm/",
CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI,
);
if (appImportConfirmUrlLoc > -1) {
jwtText = jwtText.substring(
appImportConfirmUrlLoc +
CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI.length,
);
}
const appImportOneUrlLoc = jwtText.indexOf(
CONTACT_IMPORT_ONE_URL_PATH_TIME_SAFARI,
);
if (appImportOneUrlLoc > -1) {
jwtText = jwtText.substring(
appImportOneUrlLoc + CONTACT_IMPORT_ONE_URL_PATH_TIME_SAFARI.length,
);
CONTACT_URL_PATH_ENDORSER_CH_OLD,
];
// Try each pattern
for (const pattern of URL_PATTERNS) {
const patternIndex = jwtText.indexOf(pattern);
if (patternIndex > -1) {
jwtText = jwtText.substring(patternIndex + pattern.length);
break;
}
}
const endorserUrlPathLoc = jwtText.indexOf(CONTACT_URL_PATH_ENDORSER_CH_OLD);
if (endorserUrlPathLoc > -1) {
jwtText = jwtText.substring(
endorserUrlPathLoc + CONTACT_URL_PATH_ENDORSER_CH_OLD.length,
);
// If no patterns matched but text starts with 'ey', assume it's already a JWT
if (jwtText === jwtUrlText && jwtText.startsWith("ey")) {
return jwtText;
}
// Clean up any trailing URL parameters or fragments
const endIndex = jwtText.indexOf("?");
if (endIndex > -1) {
jwtText = jwtText.substring(0, endIndex);
}
return jwtText;
};

31
src/libs/crypto/vc/index.ts

@ -126,7 +126,36 @@ function bytesToHex(b: Uint8Array): string {
// We should be calling 'verify' in more places, showing warnings if it fails.
// @returns JWTDecoded with { header: JWTHeader, payload: any, signature: string, data: string } (but doesn't verify the signature)
export function decodeEndorserJwt(jwt: string) {
return didJwt.decodeJWT(jwt);
try {
// First try the standard did-jwt decode
return didJwt.decodeJWT(jwt);
} catch (error) {
// If that fails, try manual decoding
try {
const parts = jwt.split(".");
if (parts.length !== 3) {
throw new Error("JWT must have 3 parts");
}
const header = JSON.parse(Buffer.from(parts[0], "base64url").toString());
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
// Validate the header
if (header.typ !== "JWT" || !header.alg) {
throw new Error("Invalid JWT header format");
}
// Return in the same format as didJwt.decodeJWT
return {
header,
payload,
signature: parts[2],
data: parts[0] + "." + parts[1],
};
} catch (e) {
throw new Error(`invalid_argument: Incorrect format JWT - ${e.message}`);
}
}
}
// return Promise of at least { issuer, payload, verified boolean }

288
src/views/ContactQRScanShowView.vue

@ -116,7 +116,7 @@
<script lang="ts">
import { AxiosError } from "axios";
import QRCodeVue3 from "qr-code-generator-vue3";
import { Component, Vue } from "vue-facing-decorator";
import { Component, Vue, Ref } from "vue-facing-decorator";
import { QrcodeStream } from "vue-qrcode-reader";
import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
import { PlatformService } from "../services/PlatformService";
@ -137,7 +137,7 @@ import {
BarcodeScanner,
type ScanResult,
} from "@capacitor-mlkit/barcode-scanning";
import { ref, reactive } from "vue";
import { reactive } from "vue";
// Declare global constants
declare const __USE_QR_READER__: boolean;
@ -205,6 +205,19 @@ interface AppState {
scannerState: ScannerState;
}
interface Barcode {
rawValue: string;
bytes?: number[];
}
interface MLKitScanResult {
barcodes: Barcode[];
}
interface WebQRResult {
rawValue: string;
}
@Component({
components: {
QRCodeVue3,
@ -216,6 +229,11 @@ interface AppState {
export default class ContactQRScanShowView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
$router!: Router;
@Ref()
readonly userNameDialog!: {
open: (callback: (name: string) => void) => void;
};
declare $refs: {
userNameDialog: {
open: (callback: (name: string) => void) => void;
@ -423,42 +441,7 @@ export default class ContactQRScanShowView extends Vue {
this.lastCameraState = state;
}
beforeDestroy() {
logger.log(
"ContactQRScanShow component being destroyed, initiating cleanup",
);
// Clean up scanner
this.stopScanning().catch((error) => {
logger.error("Error stopping scanner during destroy:", error);
});
// Remove all app lifecycle listeners
const cleanupListeners = async () => {
if (this.appStateListener) {
try {
await this.appStateListener.remove();
logger.log("App state change listener removed successfully");
} catch (error) {
logger.error("Error removing app state change listener:", error);
}
}
try {
await App.removeAllListeners();
logger.log("All app listeners removed successfully");
} catch (error) {
logger.error("Error removing all app listeners:", error);
}
};
// Cleanup everything
Promise.all([cleanupListeners(), this.cleanupCamera()]).catch((error) => {
logger.error("Error during component cleanup:", error);
});
}
async openMobileCamera() {
private async openMobileCamera() {
try {
this.state.isProcessing = true;
this.state.processingStatus = "Starting camera...";
@ -466,7 +449,7 @@ export default class ContactQRScanShowView extends Vue {
// Check current permission status
const status = await BarcodeScanner.checkPermissions();
logger.log("Camera permission status:", JSON.stringify(status, null, 2));
logger.log("Camera permission status:", status);
if (status.camera !== "granted") {
// Request permission if not granted
@ -475,36 +458,32 @@ export default class ContactQRScanShowView extends Vue {
if (permissionStatus.camera !== "granted") {
throw new Error("Camera permission not granted");
}
logger.log(
"Camera permission granted:",
JSON.stringify(permissionStatus, null, 2),
);
logger.log("Camera permission granted:", permissionStatus);
}
// Remove any existing listener first
try {
if (this.scanListener) {
logger.log("Removing existing barcode listener");
await this.scanListener.remove();
this.scanListener = null;
}
} catch (error) {
logger.error("Error removing existing listener:", error);
// Continue with setup even if removal fails
}
await this.cleanupScanListener();
// Set up the listener before starting the scan
logger.log("Setting up new barcode listener");
this.scanListener = await BarcodeScanner.addListener(
"barcodesScanned",
async (result: ScanResult) => {
logger.log(
"Barcode scan result received:",
JSON.stringify(result, null, 2),
);
if (result.barcodes && result.barcodes.length > 0) {
this.state.processingDetails = `Processing QR code: ${result.barcodes[0].rawValue}`;
await this.handleScanResult(result.barcodes[0].rawValue);
try {
logger.log("Barcode scan result received:", result);
if (result.barcodes && result.barcodes.length > 0) {
const barcode = result.barcodes[0];
if (!barcode.rawValue) {
logger.warn("Received empty barcode value");
return;
}
this.state.processingDetails = `Processing QR code: ${barcode.rawValue}`;
await this.handleScanResult(barcode.rawValue);
}
} catch (error) {
logger.error("Error processing barcode result:", error);
this.showError("Failed to process QR code");
}
},
);
@ -514,7 +493,7 @@ export default class ContactQRScanShowView extends Vue {
logger.log("Starting barcode scanner");
await BarcodeScanner.startScan();
logger.log("Barcode scanner started successfully");
this.state.isProcessing = false;
this.state.processingStatus = "";
} catch (error) {
@ -525,16 +504,21 @@ export default class ContactQRScanShowView extends Vue {
this.showError(
error instanceof Error ? error.message : "Failed to open camera",
);
// Cleanup on error
try {
if (this.scanListener) {
await this.scanListener.remove();
this.scanListener = null;
}
} catch (cleanupError) {
logger.error("Error during cleanup:", cleanupError);
await this.cleanupScanListener();
}
}
private async cleanupScanListener(): Promise<void> {
try {
if (this.scanListener) {
logger.log("Removing existing barcode listener");
await this.scanListener.remove();
this.scanListener = null;
}
} catch (error) {
logger.error("Error removing barcode listener:", error);
}
}
@ -543,15 +527,27 @@ export default class ContactQRScanShowView extends Vue {
this.state.isProcessing = true;
this.state.processingStatus = "Processing QR code...";
this.state.processingDetails = `Scanned value: ${rawValue}`;
logger.log("Processing scanned QR code:", rawValue);
// Stop scanning before processing
await this.stopScanning();
// Validate URL format first
if (!rawValue.startsWith("http://") && !rawValue.startsWith("https://")) {
throw new Error(
"Invalid QR code format. Please scan a valid TimeSafari contact QR code.",
);
}
// Process the scan result
await this.onScanDetect({ rawValue });
} catch (error) {
logger.error("Error handling scan result:", error);
this.showError("Failed to process scan result");
this.showError(
error instanceof Error
? error.message
: "Failed to process scan result",
);
} finally {
this.state.isProcessing = false;
this.state.processingStatus = "";
@ -594,93 +590,110 @@ export default class ContactQRScanShowView extends Vue {
}
/**
*
* @param content is the result of a QR scan, an array with one item with a rawValue property
* Handle QR code scan result
* @param content scan result from barcode scanner
*/
// Unfortunately, there are not typescript definitions for the qrcode-stream component yet.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async onScanDetect(content: any): Promise<void> {
const url = content[0]?.rawValue;
if (!url) {
this.danger("No QR code detected. Please try again.", "Scan Error");
return;
async onScanDetect(content: unknown): Promise<void> {
// Extract URL from different possible formats
let url: string | null = null;
if (typeof content === "object" && content !== null) {
// Handle Capacitor MLKit scanner format
if (
"barcodes" in content &&
Array.isArray((content as MLKitScanResult).barcodes)
) {
const mlkitResult = content as MLKitScanResult;
url = mlkitResult.barcodes[0]?.rawValue;
}
// Handle web QR reader format
else if (Array.isArray(content)) {
const webResult = content as WebQRResult[];
url = webResult[0]?.rawValue;
}
// Handle direct object format
else if ("rawValue" in content) {
const directResult = content as WebQRResult;
url = directResult.rawValue;
}
}
// Handle direct string format
else if (typeof content === "string") {
url = content;
}
// Validate URL format first
if (!url.startsWith("http://") && !url.startsWith("https://")) {
this.danger(
"Invalid QR code format. Please scan a valid TimeSafari contact QR code.",
"Invalid Format",
if (!url) {
logger.error("No valid QR code URL detected");
this.$notify(
{
group: "alert",
type: "danger",
title: "Invalid Contact QR Code",
text: "No QR code detected with contact information.",
},
5000,
);
return;
}
let newContact: Contact;
try {
// Extract JWT from URL
logger.log("Attempting to extract JWT from URL:", url);
const jwt = getContactJwtFromJwtUrl(url);
if (!jwt) {
this.danger(
"Could not extract contact information from the QR code. Please try again.",
"Invalid QR Code",
);
return;
}
// Validate JWT format
if (
!jwt.match(/^[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*$/)
) {
this.danger(
"The QR code contains invalid data. Please scan a valid TimeSafari contact QR code.",
"Invalid Data",
logger.error("Failed to extract JWT from URL");
this.$notify(
{
group: "alert",
type: "danger",
title: "Invalid QR Code",
text: "Could not extract contact information from QR code.",
},
3000,
);
return;
}
logger.log("Successfully extracted JWT, attempting to decode");
const { payload } = decodeEndorserJwt(jwt);
if (!payload) {
this.danger(
"Could not decode the contact information. Please try again.",
"Decode Error",
);
logger.error("JWT payload is null or undefined");
this.danger("Invalid JWT format", "Contact Error");
return;
}
// Validate required fields
if (!payload.own && !payload.iss) {
this.danger(
"Missing required contact information. Please scan a valid TimeSafari contact QR code.",
"Incomplete Data",
);
if (!payload.own) {
logger.error("JWT payload missing 'own' property");
this.danger("Contact information is incomplete", "Contact Error");
return;
}
newContact = {
did: payload.own?.did || payload.iss,
name: payload.own?.name,
nextPubKeyHashB64: payload.own?.nextPublicEncKeyHash,
profileImageUrl: payload.own?.profileImageUrl,
publicKeyBase64: payload.own?.publicEncKey,
registered: payload.own?.registered,
did: payload.own.did || payload.iss,
name: payload.own.name || "",
nextPubKeyHashB64: payload.own.nextPublicEncKeyHash || "",
profileImageUrl: payload.own.profileImageUrl || "",
publicKeyBase64: payload.own.publicEncKey || "",
registered: payload.own.registered || false,
};
if (!newContact.did) {
this.danger(
"Missing contact identifier. Please scan a valid TimeSafari contact QR code.",
"Incomplete Contact",
);
logger.error("Contact missing DID");
this.danger("Contact is missing identifier", "Invalid Contact");
return;
}
if (!isDid(newContact.did)) {
this.danger(
"Invalid contact identifier format. The identifier must begin with 'did:'.",
"Invalid Identifier",
);
logger.error("Invalid DID format:", newContact.did);
this.danger("Invalid contact identifier format", "Invalid Contact");
return;
}
logger.log("Saving new contact:", {
...newContact,
publicKeyBase64: "[REDACTED]",
});
await db.open();
await db.contacts.add(newContact);
@ -741,10 +754,15 @@ export default class ContactQRScanShowView extends Vue {
}, 500);
}
} catch (e) {
logger.error("Error processing QR code:", e);
this.danger(
"Could not process the QR code. Please make sure you're scanning a valid TimeSafari contact QR code.",
"Processing Error",
logger.error("Error processing contact QR code:", e);
this.$notify(
{
group: "alert",
type: "danger",
title: "Contact Error",
text: "Could not process contact information. Please try scanning again.",
},
5000,
);
}
}
@ -967,5 +985,21 @@ export default class ContactQRScanShowView extends Vue {
this.state.error = errorMessage;
this.state.scannerState.error = errorMessage;
}
async beforeDestroy() {
logger.log(
"ContactQRScanShow component being destroyed, initiating cleanup",
);
// Clean up scanner
await Promise.all([
this.stopScanning(),
this.cleanupScanListener(),
this.cleanupAppListeners(),
this.cleanupCamera(),
]).catch((error) => {
logger.error("Error during component cleanup:", error);
});
}
}
</script>

Loading…
Cancel
Save