@qafka/react-native 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/CONTRIBUTING.md +92 -0
  3. package/LICENSE +22 -0
  4. package/README.md +109 -0
  5. package/SECURITY.md +67 -0
  6. package/android/build.gradle +35 -0
  7. package/android/src/main/AndroidManifest.xml +2 -0
  8. package/android/src/main/java/com/qafka/attestation/QafkaAttestationModule.kt +92 -0
  9. package/android/src/main/java/com/qafka/attestation/QafkaAttestationPackage.kt +22 -0
  10. package/android/src/main/java/com/qafka/audio/QafkaAudioModule.kt +290 -0
  11. package/android/src/main/java/com/qafka/clipboard/QafkaClipboardModule.kt +28 -0
  12. package/android/src/main/java/com/qafka/storage/QafkaStorageModule.kt +80 -0
  13. package/app.plugin.js +1 -0
  14. package/dist/QafkaSDK.d.ts +174 -0
  15. package/dist/QafkaSDK.js +461 -0
  16. package/dist/cards/bindings/resolveFieldName.d.ts +25 -0
  17. package/dist/cards/bindings/resolveFieldName.js +82 -0
  18. package/dist/cards/cta/CardContext.d.ts +16 -0
  19. package/dist/cards/cta/CardContext.js +58 -0
  20. package/dist/cards/cta/dispatcher.d.ts +7 -0
  21. package/dist/cards/cta/dispatcher.js +90 -0
  22. package/dist/cards/cta/types.d.ts +66 -0
  23. package/dist/cards/cta/types.js +2 -0
  24. package/dist/cards/index.d.ts +20 -0
  25. package/dist/cards/index.js +34 -0
  26. package/dist/cards/primitives/QButton.d.ts +10 -0
  27. package/dist/cards/primitives/QButton.js +115 -0
  28. package/dist/cards/primitives/QDivider.d.ts +7 -0
  29. package/dist/cards/primitives/QDivider.js +17 -0
  30. package/dist/cards/primitives/QIcon.d.ts +13 -0
  31. package/dist/cards/primitives/QIcon.js +26 -0
  32. package/dist/cards/primitives/QImage.d.ts +9 -0
  33. package/dist/cards/primitives/QImage.js +22 -0
  34. package/dist/cards/primitives/QText.d.ts +9 -0
  35. package/dist/cards/primitives/QText.js +30 -0
  36. package/dist/cards/primitives/QView.d.ts +8 -0
  37. package/dist/cards/primitives/QView.js +19 -0
  38. package/dist/cards/renderer/CardRenderer.d.ts +19 -0
  39. package/dist/cards/renderer/CardRenderer.js +64 -0
  40. package/dist/cards/renderer/renderNode.d.ts +13 -0
  41. package/dist/cards/renderer/renderNode.js +42 -0
  42. package/dist/cards/types.d.ts +110 -0
  43. package/dist/cards/types.js +6 -0
  44. package/dist/components/ActionResultBadge.d.ts +12 -0
  45. package/dist/components/ActionResultBadge.js +58 -0
  46. package/dist/components/ChatPage.d.ts +44 -0
  47. package/dist/components/ChatPage.js +84 -0
  48. package/dist/components/DataChip.d.ts +8 -0
  49. package/dist/components/DataChip.js +80 -0
  50. package/dist/components/DataChipList.d.ts +13 -0
  51. package/dist/components/DataChipList.js +21 -0
  52. package/dist/components/FloatingButton.d.ts +11 -0
  53. package/dist/components/FloatingButton.js +162 -0
  54. package/dist/components/InputArea.d.ts +57 -0
  55. package/dist/components/InputArea.js +142 -0
  56. package/dist/components/MarkdownText.d.ts +15 -0
  57. package/dist/components/MarkdownText.js +283 -0
  58. package/dist/components/MessageBubble.d.ts +134 -0
  59. package/dist/components/MessageBubble.js +384 -0
  60. package/dist/components/NavigationSuggestion.d.ts +11 -0
  61. package/dist/components/NavigationSuggestion.js +109 -0
  62. package/dist/components/Qafka.d.ts +39 -0
  63. package/dist/components/Qafka.handlers.d.ts +21 -0
  64. package/dist/components/Qafka.handlers.js +54 -0
  65. package/dist/components/Qafka.js +493 -0
  66. package/dist/components/Qafka.styles.d.ts +19 -0
  67. package/dist/components/Qafka.styles.js +101 -0
  68. package/dist/components/Qafka.types.d.ts +744 -0
  69. package/dist/components/Qafka.types.js +2 -0
  70. package/dist/components/Qafka.utils.d.ts +7 -0
  71. package/dist/components/Qafka.utils.js +34 -0
  72. package/dist/components/QafkaProvider.d.ts +12 -0
  73. package/dist/components/QafkaProvider.js +87 -0
  74. package/dist/components/QuickReplies.d.ts +14 -0
  75. package/dist/components/QuickReplies.js +48 -0
  76. package/dist/components/StepProgressIndicator.d.ts +12 -0
  77. package/dist/components/StepProgressIndicator.js +48 -0
  78. package/dist/components/SuggestionButton.d.ts +42 -0
  79. package/dist/components/SuggestionButton.js +67 -0
  80. package/dist/components/ToolStatusPill.d.ts +20 -0
  81. package/dist/components/ToolStatusPill.js +43 -0
  82. package/dist/components/TypingIndicator.d.ts +28 -0
  83. package/dist/components/TypingIndicator.js +109 -0
  84. package/dist/components/VoicePage.d.ts +48 -0
  85. package/dist/components/VoicePage.js +683 -0
  86. package/dist/components/defaults/DefaultCard.d.ts +14 -0
  87. package/dist/components/defaults/DefaultCard.js +156 -0
  88. package/dist/components/defaults/DefaultDetail.d.ts +14 -0
  89. package/dist/components/defaults/DefaultDetail.js +138 -0
  90. package/dist/components/defaults/DefaultList.d.ts +12 -0
  91. package/dist/components/defaults/DefaultList.js +98 -0
  92. package/dist/components/defaults/DefaultTable.d.ts +14 -0
  93. package/dist/components/defaults/DefaultTable.js +204 -0
  94. package/dist/components/defaults/index.d.ts +14 -0
  95. package/dist/components/defaults/index.js +25 -0
  96. package/dist/components/index.d.ts +22 -0
  97. package/dist/components/index.js +36 -0
  98. package/dist/constants.d.ts +10 -0
  99. package/dist/constants.js +13 -0
  100. package/dist/hooks/useChatMessages.d.ts +72 -0
  101. package/dist/hooks/useChatMessages.js +505 -0
  102. package/dist/hooks/useContextManager.d.ts +12 -0
  103. package/dist/hooks/useContextManager.js +46 -0
  104. package/dist/hooks/useProjectTheme.d.ts +19 -0
  105. package/dist/hooks/useProjectTheme.js +163 -0
  106. package/dist/hooks/useSDK.d.ts +31 -0
  107. package/dist/hooks/useSDK.js +103 -0
  108. package/dist/hooks/useVoiceChat.d.ts +110 -0
  109. package/dist/hooks/useVoiceChat.js +436 -0
  110. package/dist/index.d.ts +13 -0
  111. package/dist/index.js +59 -0
  112. package/dist/native/QafkaAttestation.d.ts +23 -0
  113. package/dist/native/QafkaAttestation.js +70 -0
  114. package/dist/native/QafkaAudio.d.ts +14 -0
  115. package/dist/native/QafkaAudio.js +31 -0
  116. package/dist/native/QafkaClipboard.d.ts +11 -0
  117. package/dist/native/QafkaClipboard.js +14 -0
  118. package/dist/native/QafkaStorage.d.ts +15 -0
  119. package/dist/native/QafkaStorage.js +12 -0
  120. package/dist/resolve-project-config.d.ts +35 -0
  121. package/dist/resolve-project-config.js +41 -0
  122. package/dist/runtime-config-loader.d.ts +37 -0
  123. package/dist/runtime-config-loader.js +53 -0
  124. package/dist/services/AttestationManager.d.ts +38 -0
  125. package/dist/services/AttestationManager.js +296 -0
  126. package/dist/services/BackendService.d.ts +156 -0
  127. package/dist/services/BackendService.js +755 -0
  128. package/dist/services/ConversationManager.d.ts +43 -0
  129. package/dist/services/ConversationManager.js +96 -0
  130. package/dist/services/NavigationHandler.d.ts +29 -0
  131. package/dist/services/NavigationHandler.js +70 -0
  132. package/dist/services/RealtimeService.d.ts +83 -0
  133. package/dist/services/RealtimeService.js +203 -0
  134. package/dist/services/storage.d.ts +11 -0
  135. package/dist/services/storage.js +15 -0
  136. package/dist/services/storageCore.d.ts +17 -0
  137. package/dist/services/storageCore.js +46 -0
  138. package/dist/themes/dark.d.ts +5 -0
  139. package/dist/themes/dark.js +129 -0
  140. package/dist/themes/index.d.ts +12 -0
  141. package/dist/themes/index.js +33 -0
  142. package/dist/themes/light.d.ts +5 -0
  143. package/dist/themes/light.js +129 -0
  144. package/dist/themes/types.d.ts +155 -0
  145. package/dist/themes/types.js +5 -0
  146. package/dist/types/chat.d.ts +126 -0
  147. package/dist/types/chat.js +5 -0
  148. package/dist/types/components.d.ts +56 -0
  149. package/dist/types/components.js +16 -0
  150. package/dist/types/external-navigation.d.ts +19 -0
  151. package/dist/types/external-navigation.js +8 -0
  152. package/dist/types/index.d.ts +9 -0
  153. package/dist/types/index.js +25 -0
  154. package/dist/types/navigation.d.ts +86 -0
  155. package/dist/types/navigation.js +5 -0
  156. package/dist/types/sdk.d.ts +36 -0
  157. package/dist/types/sdk.js +5 -0
  158. package/dist/utils/deepMerge.d.ts +46 -0
  159. package/dist/utils/deepMerge.js +70 -0
  160. package/dist/utils/fontUtils.d.ts +8 -0
  161. package/dist/utils/fontUtils.js +16 -0
  162. package/dist/validate-end-user.d.ts +18 -0
  163. package/dist/validate-end-user.js +74 -0
  164. package/expo-plugin/withQafkaAttestation.js +57 -0
  165. package/ios/QafkaAttestation.m +25 -0
  166. package/ios/QafkaAttestation.swift +128 -0
  167. package/ios/QafkaAudio.m +23 -0
  168. package/ios/QafkaAudio.swift +519 -0
  169. package/ios/QafkaClipboard.m +10 -0
  170. package/ios/QafkaClipboard.swift +21 -0
  171. package/ios/QafkaReactImports.h +2 -0
  172. package/ios/QafkaStorage.m +26 -0
  173. package/ios/QafkaStorage.swift +118 -0
  174. package/package.json +82 -0
  175. package/qafka.config.d.ts +9 -0
  176. package/qafka.config.js +9 -0
  177. package/react-native-qafka.podspec +28 -0
  178. package/react-native.config.js +14 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@qafka/react-native` are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [2.0.0] — 2026-05-17
11
+
12
+ Initial public release. See [README.md](./README.md) for the full feature list and installation instructions.
@@ -0,0 +1,92 @@
1
+ # Contributing
2
+
3
+ Thanks for your interest in Qafka.
4
+
5
+ ## About this repository
6
+
7
+ This is the official React Native SDK for the [Qafka platform](https://qafka.com). It's MIT-licensed and the source is public — audit it, debug it, pin a specific commit, fork it if you need.
8
+
9
+ Day-to-day development happens on our internal roadmap, and we accept a curated set of external contributions — see below.
10
+
11
+ ## Reporting bugs
12
+
13
+ Please use [GitHub Issues](https://github.com/qafka-ai/react-native-qafka/issues) and the bug report template. Helpful reports include:
14
+
15
+ - SDK version, React Native version, platform (iOS / Android / Expo)
16
+ - A minimal reproduction
17
+ - Logs (with API keys redacted)
18
+
19
+ For **security issues**, see [SECURITY.md](./SECURITY.md) — please do not file them as public issues.
20
+
21
+ ## Requesting features
22
+
23
+ Open a [GitHub Issue](https://github.com/qafka-ai/react-native-qafka/issues) describing the use case. We'll respond with whether it fits the roadmap and the likely timing.
24
+
25
+ **Please do not send feature PRs without a tracking issue and our explicit go-ahead.** We may decline merges that don't fit our direction, even if the code is good — please don't take it personally.
26
+
27
+ ## Pull requests we accept
28
+
29
+ - 🐛 **Bug fixes** with a reproducing test
30
+ - 📝 **Documentation fixes** — typos, broken links, clarifications
31
+ - 🔧 **Build / tooling fixes** — broken CI, packaging issues
32
+ - ♿ **Accessibility fixes** to the rendered components
33
+
34
+ ## Pull requests we usually decline
35
+
36
+ - New features without a prior issue
37
+ - Pure refactors / restyles
38
+ - Dependency updates (we manage these on a release cadence)
39
+ - Code style changes that aren't enforced by our linter
40
+
41
+ ## Dev setup
42
+
43
+ ```bash
44
+ git clone https://github.com/qafka-ai/react-native-qafka.git
45
+ cd react-native-qafka
46
+ pnpm install
47
+ pnpm build
48
+ pnpm test
49
+ ```
50
+
51
+ To test changes locally in another app, we use [yalc](https://github.com/wclr/yalc):
52
+
53
+ ```bash
54
+ yalc publish --push --force --private
55
+ # in the consuming app:
56
+ yalc add @qafka/react-native
57
+ ```
58
+
59
+ ## Pull request checklist
60
+
61
+ Before opening a PR:
62
+
63
+ - [ ] Linked to a tracking issue
64
+ - [ ] Branch is up to date with `main`
65
+ - [ ] Tests added / updated for the change
66
+ - [ ] `pnpm typecheck` passes
67
+ - [ ] `pnpm test` passes
68
+ - [ ] `CHANGELOG.md` updated under `## [Unreleased]`
69
+ - [ ] Commits are signed off (DCO — see below)
70
+
71
+ ## Developer Certificate of Origin (DCO)
72
+
73
+ We require commits to be signed off with the [Developer Certificate of Origin](https://developercertificate.org/). This is a lightweight assertion that you have the right to submit your contribution.
74
+
75
+ Sign off by adding `-s` to your commit:
76
+
77
+ ```bash
78
+ git commit -s -m "fix: handle empty tool result"
79
+ ```
80
+
81
+ This appends a `Signed-off-by: Your Name <your.email@example.com>` line to your commit message.
82
+
83
+ By signing off and contributing, you agree your contributions are licensed under the [MIT License](./LICENSE).
84
+
85
+ ## Code of Conduct
86
+
87
+ Be respectful in issues, PRs, and discussions. We follow the [Contributor Covenant](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
88
+
89
+ ## Questions
90
+
91
+ For product questions, billing, or sales: [qafka.com/contact](https://qafka.com).
92
+ For SDK technical questions: open a [Discussion](https://github.com/qafka-ai/react-native-qafka/discussions) or Issue.
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Qafka
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # @qafka/react-native
2
+
3
+ [![npm](https://img.shields.io/npm/v/@qafka/react-native.svg)](https://www.npmjs.com/package/@qafka/react-native)
4
+ [![downloads](https://img.shields.io/npm/dm/@qafka/react-native.svg)](https://www.npmjs.com/package/@qafka/react-native)
5
+ [![types](https://img.shields.io/npm/types/@qafka/react-native.svg)](https://www.npmjs.com/package/@qafka/react-native)
6
+ [![license](https://img.shields.io/npm/l/@qafka/react-native.svg)](./LICENSE)
7
+ [![CI](https://github.com/qafka-ai/react-native-qafka/actions/workflows/ci.yml/badge.svg)](https://github.com/qafka-ai/react-native-qafka/actions/workflows/ci.yml)
8
+
9
+ In-app AI assistant for React Native and Expo. Drop the `<Qafka />` component into your app and your users get a chat + voice interface that understands your screens, runs your tools, and guides them through flows you define in the [Qafka dashboard](https://app.qafka.com).
10
+
11
+ ## Quickstart (recommended)
12
+
13
+ Install the CLI once, log in, then initialize Qafka in your app:
14
+
15
+ ```bash
16
+ npm install -g qafka
17
+
18
+ cd your-app
19
+ qafka login
20
+ qafka init
21
+ ```
22
+
23
+ `qafka init` installs the SDK, registers the Expo config plugin (when applicable), pulls your API key from the dashboard, and scaffolds a chat screen wired to your project. Re-run it any time you add tools or screens in the dashboard — it's idempotent and safe.
24
+
25
+ ## Manual installation
26
+
27
+ If you'd rather wire things up yourself:
28
+
29
+ ```bash
30
+ npm install @qafka/react-native
31
+ # or: pnpm add / yarn add
32
+ ```
33
+
34
+ ### Peer dependencies
35
+
36
+ ```bash
37
+ npm install react-native react-native-safe-area-context
38
+ ```
39
+
40
+ `@react-navigation/native` is optional — install it only if you want the SDK to navigate between screens for you.
41
+
42
+ ### Expo
43
+
44
+ The package ships an Expo config plugin. Add it to your `app.json` / `app.config.js`:
45
+
46
+ ```json
47
+ {
48
+ "expo": {
49
+ "plugins": ["@qafka/react-native"]
50
+ }
51
+ }
52
+ ```
53
+
54
+ Then run `npx expo prebuild` (or rebuild your dev client) so the native module is bundled.
55
+
56
+ ### Bare React Native
57
+
58
+ ```bash
59
+ cd ios && pod install
60
+ ```
61
+
62
+ Android autolinking handles the native module. If you plan to use **voice mode**, add the microphone permission to your app's `android/app/src/main/AndroidManifest.xml`:
63
+
64
+ ```xml
65
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
66
+ ```
67
+
68
+ Expo users get this automatically via the SDK's config plugin.
69
+
70
+ ## Usage
71
+
72
+ When your project is initialized with the [Qafka CLI](https://github.com/qafka-ai/qafka-cli) (`qafka init`), the SDK picks up your development key from the CLI-generated runtime config — no extra props needed:
73
+
74
+ ```tsx
75
+ import { Qafka } from '@qafka/react-native';
76
+
77
+ export default function App() {
78
+ return <Qafka />;
79
+ }
80
+ ```
81
+
82
+ The component renders a floating button that opens the chat UI. Configure tools, screens, and behavior from the dashboard — most updates need no code changes.
83
+
84
+ Pass `projectId` when your app has more than one registered project:
85
+
86
+ ```tsx
87
+ <Qafka projectId="proj_abc123" />
88
+ ```
89
+
90
+ ## Documentation
91
+
92
+ Full guides, API reference, theming, voice mode, tools, and advanced configuration:
93
+
94
+ **→ [app.qafka.com/docs](https://app.qafka.com/docs)**
95
+
96
+ ## Requirements
97
+
98
+ - React Native ≥ 0.72 (Expo SDK 49+ supported)
99
+ - React ≥ 18
100
+ - iOS 14+ / Android 6+ (API 23+)
101
+ - Node ≥ 20 (for build tooling)
102
+
103
+ ## Contributing
104
+
105
+ This SDK is the public source for a commercial product — see [CONTRIBUTING.md](./CONTRIBUTING.md) for what we accept and how to file issues. For vulnerabilities, see [SECURITY.md](./SECURITY.md).
106
+
107
+ ## License
108
+
109
+ MIT © Qafka
package/SECURITY.md ADDED
@@ -0,0 +1,67 @@
1
+ # Security Policy
2
+
3
+ Qafka takes security seriously. This document describes how to report vulnerabilities in the **React Native SDK** (`@qafka/react-native`).
4
+
5
+ ## Supported versions
6
+
7
+ Only the latest published minor version receives security updates. We recommend always running the latest version.
8
+
9
+ ## Reporting a vulnerability
10
+
11
+ **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
12
+
13
+ Instead, choose one of these private channels:
14
+
15
+ 1. **Email:** [security@qafka.com](mailto:security@qafka.com)
16
+ 2. **GitHub Security Advisories:** [Report a vulnerability privately](https://github.com/qafka-ai/react-native-qafka/security/advisories/new)
17
+
18
+ Please include:
19
+
20
+ - A clear description of the issue
21
+ - Steps to reproduce (a minimal repo or code snippet helps)
22
+ - Affected SDK version(s) and platforms (iOS / Android / Expo)
23
+ - Potential impact you've identified
24
+ - Any suggested fix, if you have one
25
+
26
+ If you'd like to encrypt your report, request our PGP key by emailing [security@qafka.com](mailto:security@qafka.com).
27
+
28
+ ## What to expect
29
+
30
+ - **Acknowledgement:** within 2 business days of your report
31
+ - **Initial assessment:** within 5 business days
32
+ - **Status updates:** at least every 7 days until the issue is resolved
33
+ - **Coordinated disclosure:** we'll work with you on a public disclosure timeline once a fix is ready
34
+ - **Credit:** with your permission, we'll credit you in the release notes and the GitHub Security Advisory
35
+
36
+ ## Scope
37
+
38
+ ### In scope
39
+
40
+ This policy covers vulnerabilities in this SDK package that could affect customer applications:
41
+
42
+ - API key, token, or credential handling within the SDK
43
+ - Native module security (iOS Swift / Objective-C, Android Kotlin / Java)
44
+ - Data leakage between sessions, projects, or users on the same device
45
+ - Local storage / cache integrity
46
+ - Bundle / dependency supply-chain issues specific to this package
47
+ - Crash or denial-of-service triggerable from the SDK's public API
48
+
49
+ ### Out of scope
50
+
51
+ - **Qafka backend (`api.qafka.com`)** — out of scope for this repository. If you find a backend issue, email [security@qafka.com](mailto:security@qafka.com) with `[backend]` in the subject.
52
+ - **Third-party dependencies** — please report to the upstream maintainer. If the issue is exploitable through our usage specifically, we'll accept it here.
53
+ - **Issues requiring a rooted / jailbroken device** or attacker-controlled physical access, unless the impact extends beyond the compromised device.
54
+ - **Social engineering** of Qafka customers or staff.
55
+ - **Outdated documentation** — please file a regular issue.
56
+
57
+ ## Safe harbor
58
+
59
+ We will not pursue legal action against researchers who:
60
+
61
+ - Make a good-faith effort to follow this policy
62
+ - Avoid privacy violations, data destruction, and service disruption
63
+ - Give us reasonable time to fix the issue before public disclosure
64
+
65
+ ## Questions
66
+
67
+ For anything not covered here, email [security@qafka.com](mailto:security@qafka.com).
@@ -0,0 +1,35 @@
1
+ apply plugin: 'com.android.library'
2
+ apply plugin: 'kotlin-android'
3
+
4
+ def safeExtGet(prop, fallback) {
5
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
6
+ }
7
+
8
+ android {
9
+ namespace "com.qafka.attestation"
10
+ compileSdkVersion safeExtGet('compileSdkVersion', 34)
11
+
12
+ defaultConfig {
13
+ minSdkVersion safeExtGet('minSdkVersion', 24)
14
+ targetSdkVersion safeExtGet('targetSdkVersion', 34)
15
+ }
16
+
17
+ compileOptions {
18
+ sourceCompatibility JavaVersion.toVersion(safeExtGet('javaVersion', 17))
19
+ targetCompatibility JavaVersion.toVersion(safeExtGet('javaVersion', 17))
20
+ }
21
+
22
+ kotlinOptions {
23
+ jvmTarget = safeExtGet('javaVersion', 17).toString()
24
+ }
25
+ }
26
+
27
+ repositories {
28
+ google()
29
+ mavenCentral()
30
+ }
31
+
32
+ dependencies {
33
+ implementation 'com.facebook.react:react-android'
34
+ implementation 'androidx.security:security-crypto:1.1.0-alpha06'
35
+ }
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,92 @@
1
+ package com.qafka.attestation
2
+
3
+ import android.os.Build
4
+ import android.security.keystore.KeyGenParameterSpec
5
+ import android.security.keystore.KeyProperties
6
+ import android.util.Base64
7
+ import com.facebook.react.bridge.*
8
+ import java.security.KeyPairGenerator
9
+ import java.security.KeyStore
10
+ import java.security.cert.Certificate
11
+
12
+ class QafkaAttestationModule(reactContext: ReactApplicationContext) :
13
+ ReactContextBaseJavaModule(reactContext) {
14
+
15
+ override fun getName(): String = "QafkaAttestation"
16
+
17
+ override fun getConstants(): MutableMap<String, Any> {
18
+ val context = reactApplicationContext
19
+ val bundleId = context.packageName ?: ""
20
+ val appVersion = try {
21
+ context.packageManager.getPackageInfo(context.packageName, 0).versionName ?: ""
22
+ } catch (e: Exception) {
23
+ ""
24
+ }
25
+ val deviceModel = "${Build.MANUFACTURER} ${Build.MODEL}".trim()
26
+ return mutableMapOf(
27
+ "bundleId" to bundleId,
28
+ "appVersion" to appVersion,
29
+ "deviceModel" to deviceModel,
30
+ )
31
+ }
32
+
33
+ @ReactMethod
34
+ fun isSupported(promise: Promise) {
35
+ // Key Attestation requires Android 8.0+ (API 26) for hardware-backed
36
+ promise.resolve(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
37
+ }
38
+
39
+ @ReactMethod
40
+ fun generateKeyPair(alias: String, challengeBase64: String, promise: Promise) {
41
+ try {
42
+ val challenge = Base64.decode(challengeBase64, Base64.DEFAULT)
43
+
44
+ // Delete existing key if any
45
+ val keyStore = KeyStore.getInstance("AndroidKeyStore")
46
+ keyStore.load(null)
47
+ if (keyStore.containsAlias(alias)) {
48
+ keyStore.deleteEntry(alias)
49
+ }
50
+
51
+ val keyPairGenerator = KeyPairGenerator.getInstance(
52
+ KeyProperties.KEY_ALGORITHM_EC,
53
+ "AndroidKeyStore"
54
+ )
55
+
56
+ val builder = KeyGenParameterSpec.Builder(alias,
57
+ KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
58
+ )
59
+ .setDigests(KeyProperties.DIGEST_SHA256)
60
+ .setAttestationChallenge(challenge)
61
+
62
+ keyPairGenerator.initialize(builder.build())
63
+ keyPairGenerator.generateKeyPair()
64
+
65
+ promise.resolve(null)
66
+ } catch (e: Exception) {
67
+ promise.reject("KEY_GEN_FAILED", e.message, e)
68
+ }
69
+ }
70
+
71
+ @ReactMethod
72
+ fun getAttestationCertChain(alias: String, promise: Promise) {
73
+ try {
74
+ val keyStore = KeyStore.getInstance("AndroidKeyStore")
75
+ keyStore.load(null)
76
+
77
+ val chain: Array<Certificate> = keyStore.getCertificateChain(alias)
78
+ ?: throw Exception("No certificate chain found for alias: $alias")
79
+
80
+ val result = Arguments.createArray()
81
+ for (cert in chain) {
82
+ val encoded = cert.encoded
83
+ val base64 = Base64.encodeToString(encoded, Base64.NO_WRAP)
84
+ result.pushString(base64)
85
+ }
86
+
87
+ promise.resolve(result)
88
+ } catch (e: Exception) {
89
+ promise.reject("CERT_CHAIN_FAILED", e.message, e)
90
+ }
91
+ }
92
+ }
@@ -0,0 +1,22 @@
1
+ package com.qafka.attestation
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+ import com.qafka.audio.QafkaAudioModule
8
+ import com.qafka.clipboard.QafkaClipboardModule
9
+ import com.qafka.storage.QafkaStorageModule
10
+
11
+ class QafkaAttestationPackage : ReactPackage {
12
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> =
13
+ listOf(
14
+ QafkaAttestationModule(reactContext),
15
+ QafkaAudioModule(reactContext),
16
+ QafkaClipboardModule(reactContext),
17
+ QafkaStorageModule(reactContext),
18
+ )
19
+
20
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
21
+ emptyList()
22
+ }