react-native-privacy-guard-kit 0.1.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 (60) hide show
  1. package/LICENSE +20 -0
  2. package/PrivacyGuardKit.podspec +27 -0
  3. package/README.md +320 -0
  4. package/android/CMakeLists.txt +47 -0
  5. package/android/build.gradle +64 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/com/privacyguardkit/PrivacyGuardKitPackage.kt +17 -0
  8. package/android/src/main/java/com/privacyguardkit/Privacyguardkitmodule .kt +208 -0
  9. package/android/src/main/java/com/privacyguardkit/Screenshotobserver.kt +66 -0
  10. package/android/src/main/java/com/privacyguardkit/Secureview.kt +104 -0
  11. package/android/src/main/java/com/privacyguardkit/Secureviewmanager.kt +27 -0
  12. package/android/src/main/jni/react/renderer/components/PrivacyGuardKitViewSpec/RNSecureViewComponentDescriptor.h +25 -0
  13. package/ios/PrivacyGuardKit-Umbrella.h +14 -0
  14. package/ios/PrivacyGuardKit.m +38 -0
  15. package/ios/PrivacyGuardKit.swift +221 -0
  16. package/ios/RNSecureViewComponentView.h +16 -0
  17. package/ios/RNSecureViewComponentView.mm +84 -0
  18. package/ios/RNSecureViewManager.mm +48 -0
  19. package/lib/module/Hooks.js +119 -0
  20. package/lib/module/Hooks.js.map +1 -0
  21. package/lib/module/NativePrivacyGuardKit.js +12 -0
  22. package/lib/module/NativePrivacyGuardKit.js.map +1 -0
  23. package/lib/module/PrivacyGuardProvider.js +99 -0
  24. package/lib/module/PrivacyGuardProvider.js.map +1 -0
  25. package/lib/module/PrivacyGuardkitApi.js +104 -0
  26. package/lib/module/PrivacyGuardkitApi.js.map +1 -0
  27. package/lib/module/SecureView.js +24 -0
  28. package/lib/module/SecureView.js.map +1 -0
  29. package/lib/module/index.js +16 -0
  30. package/lib/module/index.js.map +1 -0
  31. package/lib/module/package.json +1 -0
  32. package/lib/module/specs/RNSecureViewNativeComponent.ts +19 -0
  33. package/lib/module/types.js +2 -0
  34. package/lib/module/types.js.map +1 -0
  35. package/lib/typescript/package.json +1 -0
  36. package/lib/typescript/src/Hooks.d.ts +29 -0
  37. package/lib/typescript/src/Hooks.d.ts.map +1 -0
  38. package/lib/typescript/src/NativePrivacyGuardKit.d.ts +4 -0
  39. package/lib/typescript/src/NativePrivacyGuardKit.d.ts.map +1 -0
  40. package/lib/typescript/src/PrivacyGuardProvider.d.ts +30 -0
  41. package/lib/typescript/src/PrivacyGuardProvider.d.ts.map +1 -0
  42. package/lib/typescript/src/PrivacyGuardkitApi.d.ts +45 -0
  43. package/lib/typescript/src/PrivacyGuardkitApi.d.ts.map +1 -0
  44. package/lib/typescript/src/SecureView.d.ts +10 -0
  45. package/lib/typescript/src/SecureView.d.ts.map +1 -0
  46. package/lib/typescript/src/index.d.ts +6 -0
  47. package/lib/typescript/src/index.d.ts.map +1 -0
  48. package/lib/typescript/src/specs/RNSecureViewNativeComponent.d.ts +11 -0
  49. package/lib/typescript/src/specs/RNSecureViewNativeComponent.d.ts.map +1 -0
  50. package/lib/typescript/src/types.d.ts +29 -0
  51. package/lib/typescript/src/types.d.ts.map +1 -0
  52. package/package.json +174 -0
  53. package/src/Hooks.ts +138 -0
  54. package/src/NativePrivacyGuardKit.ts +13 -0
  55. package/src/PrivacyGuardProvider.tsx +134 -0
  56. package/src/PrivacyGuardkitApi.ts +123 -0
  57. package/src/SecureView.tsx +29 -0
  58. package/src/index.tsx +37 -0
  59. package/src/specs/RNSecureViewNativeComponent.ts +19 -0
  60. package/src/types.ts +34 -0
@@ -0,0 +1,221 @@
1
+ // PrivacyGuardKit.swift
2
+ // The @objc(PrivacyGuardKit) annotation is what generates
3
+ // _OBJC_CLASS_$_PrivacyGuardKit that the linker needs.
4
+ // The class name MUST match the RCT_EXTERN_MODULE name in PrivacyGuardKit.m
5
+
6
+ import Foundation
7
+ import UIKit
8
+ import React
9
+
10
+ @objc(PrivacyGuardKit)
11
+ class PrivacyGuardKit: RCTEventEmitter {
12
+
13
+ static let screenshotTakenEvent = "onScreenshotTaken"
14
+ static let recordingStartedEvent = "onScreenRecordingStarted"
15
+ static let recordingStoppedEvent = "onScreenRecordingStopped"
16
+
17
+ private var isCaptureDisabled = false
18
+ private var isAppSwitcherGuarded = false
19
+ private var secureOverlay: UIView?
20
+ private var appSwitcherOverlay: UIView?
21
+
22
+ override static func moduleName() -> String! { "PrivacyGuardKit" }
23
+ override static func requiresMainQueueSetup() -> Bool { true }
24
+
25
+ override func supportedEvents() -> [String]! {
26
+ [
27
+ PrivacyGuardKit.screenshotTakenEvent,
28
+ PrivacyGuardKit.recordingStartedEvent,
29
+ PrivacyGuardKit.recordingStoppedEvent,
30
+ ]
31
+ }
32
+
33
+ // MARK: - Screen Capture
34
+
35
+ @objc(disableScreenCapture:reject:)
36
+ func disableScreenCapture(
37
+ _ resolve: @escaping RCTPromiseResolveBlock,
38
+ reject: @escaping RCTPromiseRejectBlock
39
+ ) {
40
+ DispatchQueue.main.async {
41
+ self.addSecureOverlay()
42
+ self.isCaptureDisabled = true
43
+ resolve(true)
44
+ }
45
+ }
46
+
47
+ @objc(enableScreenCapture:reject:)
48
+ func enableScreenCapture(
49
+ _ resolve: @escaping RCTPromiseResolveBlock,
50
+ reject: @escaping RCTPromiseRejectBlock
51
+ ) {
52
+ DispatchQueue.main.async {
53
+ self.removeSecureOverlay()
54
+ self.isCaptureDisabled = false
55
+ resolve(true)
56
+ }
57
+ }
58
+
59
+ @objc(isScreenCaptureDisabled:reject:)
60
+ func isScreenCaptureDisabled(
61
+ _ resolve: @escaping RCTPromiseResolveBlock,
62
+ reject: @escaping RCTPromiseRejectBlock
63
+ ) {
64
+ resolve(isCaptureDisabled)
65
+ }
66
+
67
+ private func addSecureOverlay() {
68
+ guard let window = currentWindow(), secureOverlay == nil else { return }
69
+ let field = UITextField()
70
+ field.isSecureTextEntry = true
71
+ field.translatesAutoresizingMaskIntoConstraints = false
72
+ let container = UIView()
73
+ container.isUserInteractionEnabled = false
74
+ container.translatesAutoresizingMaskIntoConstraints = false
75
+ container.addSubview(field)
76
+ window.addSubview(container)
77
+ NSLayoutConstraint.activate([
78
+ container.leadingAnchor.constraint(equalTo: window.leadingAnchor),
79
+ container.trailingAnchor.constraint(equalTo: window.trailingAnchor),
80
+ container.topAnchor.constraint(equalTo: window.topAnchor),
81
+ container.bottomAnchor.constraint(equalTo: window.bottomAnchor),
82
+ field.widthAnchor.constraint(equalTo: container.widthAnchor),
83
+ field.heightAnchor.constraint(equalTo: container.heightAnchor),
84
+ field.centerXAnchor.constraint(equalTo: container.centerXAnchor),
85
+ field.centerYAnchor.constraint(equalTo: container.centerYAnchor),
86
+ ])
87
+ window.sendSubviewToBack(container)
88
+ secureOverlay = container
89
+ }
90
+
91
+ private func removeSecureOverlay() {
92
+ secureOverlay?.removeFromSuperview()
93
+ secureOverlay = nil
94
+ }
95
+
96
+ // MARK: - Screen Recording
97
+
98
+ @objc(isScreenBeingRecorded:reject:)
99
+ func isScreenBeingRecorded(
100
+ _ resolve: @escaping RCTPromiseResolveBlock,
101
+ reject: @escaping RCTPromiseRejectBlock
102
+ ) {
103
+ resolve(UIScreen.main.isCaptured)
104
+ }
105
+
106
+ @objc(startScreenshotListener:reject:)
107
+ func startScreenshotListener(
108
+ _ resolve: @escaping RCTPromiseResolveBlock,
109
+ reject: @escaping RCTPromiseRejectBlock
110
+ ) {
111
+ NotificationCenter.default.removeObserver(self)
112
+ NotificationCenter.default.addObserver(
113
+ self, selector: #selector(handleScreenshot),
114
+ name: UIApplication.userDidTakeScreenshotNotification, object: nil)
115
+ NotificationCenter.default.addObserver(
116
+ self, selector: #selector(handleRecordingChange),
117
+ name: UIScreen.capturedDidChangeNotification, object: nil)
118
+ resolve(true)
119
+ }
120
+
121
+ @objc(stopScreenshotListener:reject:)
122
+ func stopScreenshotListener(
123
+ _ resolve: @escaping RCTPromiseResolveBlock,
124
+ reject: @escaping RCTPromiseRejectBlock
125
+ ) {
126
+ NotificationCenter.default.removeObserver(
127
+ self, name: UIApplication.userDidTakeScreenshotNotification, object: nil)
128
+ NotificationCenter.default.removeObserver(
129
+ self, name: UIScreen.capturedDidChangeNotification, object: nil)
130
+ resolve(true)
131
+ }
132
+
133
+ @objc private func handleScreenshot() {
134
+ sendEvent(withName: PrivacyGuardKit.screenshotTakenEvent, body: nil)
135
+ }
136
+
137
+ @objc private func handleRecordingChange() {
138
+ let recording = UIScreen.main.isCaptured
139
+ sendEvent(
140
+ withName: recording
141
+ ? PrivacyGuardKit.recordingStartedEvent
142
+ : PrivacyGuardKit.recordingStoppedEvent,
143
+ body: ["isRecording": recording])
144
+ }
145
+
146
+ // MARK: - App Switcher
147
+
148
+ @objc(enableAppSwitcherProtection:reject:)
149
+ func enableAppSwitcherProtection(
150
+ _ resolve: @escaping RCTPromiseResolveBlock,
151
+ reject: @escaping RCTPromiseRejectBlock
152
+ ) {
153
+ DispatchQueue.main.async {
154
+ NotificationCenter.default.addObserver(
155
+ self, selector: #selector(self.appWillResignActive),
156
+ name: UIApplication.willResignActiveNotification, object: nil)
157
+ NotificationCenter.default.addObserver(
158
+ self, selector: #selector(self.appDidBecomeActive),
159
+ name: UIApplication.didBecomeActiveNotification, object: nil)
160
+ self.isAppSwitcherGuarded = true
161
+ resolve(true)
162
+ }
163
+ }
164
+
165
+ @objc(disableAppSwitcherProtection:reject:)
166
+ func disableAppSwitcherProtection(
167
+ _ resolve: @escaping RCTPromiseResolveBlock,
168
+ reject: @escaping RCTPromiseRejectBlock
169
+ ) {
170
+ DispatchQueue.main.async {
171
+ NotificationCenter.default.removeObserver(
172
+ self, name: UIApplication.willResignActiveNotification, object: nil)
173
+ NotificationCenter.default.removeObserver(
174
+ self, name: UIApplication.didBecomeActiveNotification, object: nil)
175
+ self.removeAppSwitcherOverlay()
176
+ self.isAppSwitcherGuarded = false
177
+ resolve(true)
178
+ }
179
+ }
180
+
181
+ @objc private func appWillResignActive() {
182
+ guard let window = currentWindow() else { return }
183
+ let overlay = UIView(frame: window.bounds)
184
+ overlay.backgroundColor = .systemBackground
185
+ overlay.autoresizingMask = [.flexibleWidth, .flexibleHeight]
186
+ window.addSubview(overlay)
187
+ appSwitcherOverlay = overlay
188
+ }
189
+
190
+ @objc private func appDidBecomeActive() {
191
+ removeAppSwitcherOverlay()
192
+ }
193
+
194
+ private func removeAppSwitcherOverlay() {
195
+ appSwitcherOverlay?.removeFromSuperview()
196
+ appSwitcherOverlay = nil
197
+ }
198
+
199
+ // MARK: - Clipboard
200
+
201
+ @objc(clearClipboard:reject:)
202
+ func clearClipboard(
203
+ _ resolve: @escaping RCTPromiseResolveBlock,
204
+ reject: @escaping RCTPromiseRejectBlock
205
+ ) {
206
+ UIPasteboard.general.items = []
207
+ resolve(true)
208
+ }
209
+
210
+ // MARK: - Helpers
211
+
212
+ private func currentWindow() -> UIWindow? {
213
+ if #available(iOS 13.0, *) {
214
+ return UIApplication.shared.connectedScenes
215
+ .compactMap { $0 as? UIWindowScene }
216
+ .flatMap { $0.windows }
217
+ .first { $0.isKeyWindow }
218
+ }
219
+ return UIApplication.shared.keyWindow
220
+ }
221
+ }
@@ -0,0 +1,16 @@
1
+ // RNSecureViewComponentView.h
2
+
3
+ #ifdef RCT_NEW_ARCH_ENABLED
4
+
5
+ #import <React/RCTViewComponentView.h>
6
+ #import <UIKit/UIKit.h>
7
+
8
+ NS_ASSUME_NONNULL_BEGIN
9
+
10
+ @interface RNSecureViewComponentView : RCTViewComponentView
11
+
12
+ @end
13
+
14
+ NS_ASSUME_NONNULL_END
15
+
16
+ #endif // RCT_NEW_ARCH_ENABLED
@@ -0,0 +1,84 @@
1
+ // RNSecureViewComponentView.mm
2
+ // Fabric ComponentView for RNSecureView.
3
+ //
4
+ // RN 0.76+ uses RCTAppDependencyProvider (generated in the example app
5
+ // during pod install) instead of RCTThirdPartyFabricComponentsProvider.
6
+ // That generated file calls NSClassFromString("RNSecureViewComponentView")
7
+ // to get our class — so the class name MUST match exactly.
8
+ //
9
+ // The codegenConfig.ios.componentProvider in package.json tells the
10
+ // code generator: "RNSecureView" → "RNSecureViewComponentView"
11
+
12
+ #ifdef RCT_NEW_ARCH_ENABLED
13
+
14
+ #import "RNSecureViewComponentView.h"
15
+
16
+ #import <react/renderer/components/PrivacyGuardKitViewSpec/ComponentDescriptors.h>
17
+ #import <react/renderer/components/PrivacyGuardKitViewSpec/Props.h>
18
+ #import <react/renderer/components/PrivacyGuardKitViewSpec/RCTComponentViewHelpers.h>
19
+
20
+ using namespace facebook::react;
21
+
22
+ @interface RNSecureViewComponentView () <RCTRNSecureViewViewProtocol>
23
+ @end
24
+
25
+ @implementation RNSecureViewComponentView
26
+
27
+ - (instancetype)initWithFrame:(CGRect)frame {
28
+ if (self = [super initWithFrame:frame]) {
29
+ self.backgroundColor = UIColor.clearColor;
30
+ }
31
+ return self;
32
+ }
33
+
34
+ - (void)updateProps:(const Props::Shared &)props
35
+ oldProps:(const Props::Shared &)oldProps {
36
+ const auto &newProps =
37
+ *std::static_pointer_cast<const RNSecureViewProps>(props);
38
+ if (newProps.isCopyPasteDisabled) {
39
+ [self disableCopyPasteIn:self];
40
+ } else {
41
+ [self enableCopyPasteIn:self];
42
+ }
43
+ [super updateProps:props oldProps:oldProps];
44
+ }
45
+
46
+ + (ComponentDescriptorProvider)componentDescriptorProvider {
47
+ return concreteComponentDescriptorProvider<RNSecureViewComponentDescriptor>();
48
+ }
49
+
50
+ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
51
+ if (_props) {
52
+ const auto &p = *std::static_pointer_cast<const RNSecureViewProps>(_props);
53
+ if (p.isCopyPasteDisabled) return NO;
54
+ }
55
+ return [super canPerformAction:action withSender:sender];
56
+ }
57
+
58
+ - (void)disableCopyPasteIn:(UIView *)v {
59
+ for (UIView *sub in v.subviews) {
60
+ if ([sub isKindOfClass:UITextField.class])
61
+ ((UITextField *)sub).userInteractionEnabled = NO;
62
+ if ([sub isKindOfClass:UITextView.class]) {
63
+ ((UITextView *)sub).selectable = NO;
64
+ ((UITextView *)sub).editable = NO;
65
+ }
66
+ [self disableCopyPasteIn:sub];
67
+ }
68
+ }
69
+
70
+ - (void)enableCopyPasteIn:(UIView *)v {
71
+ for (UIView *sub in v.subviews) {
72
+ if ([sub isKindOfClass:UITextField.class])
73
+ ((UITextField *)sub).userInteractionEnabled = YES;
74
+ if ([sub isKindOfClass:UITextView.class]) {
75
+ ((UITextView *)sub).selectable = YES;
76
+ ((UITextView *)sub).editable = YES;
77
+ }
78
+ [self enableCopyPasteIn:sub];
79
+ }
80
+ }
81
+
82
+ @end
83
+
84
+ #endif // RCT_NEW_ARCH_ENABLED
@@ -0,0 +1,48 @@
1
+ // RNSecureViewManager.mm
2
+ // Must be .mm not .m — RCT macros expand to ObjC++ in some RN versions.
3
+
4
+ #import <React/RCTViewManager.h>
5
+ #import <React/RCTUIManager.h>
6
+ #import <UIKit/UIKit.h>
7
+
8
+ // ─────────────────────────────────────────────────────────────
9
+ // SecureView — a UIView that blocks copy/paste at the ObjC level.
10
+ // Used by the Paper (Old Architecture) path only.
11
+ // Fabric uses RNSecureViewComponentView.mm instead.
12
+ // ─────────────────────────────────────────────────────────────
13
+
14
+ @interface RNSecureUIView : UIView
15
+ @property (nonatomic, assign) BOOL isCopyPasteDisabled;
16
+ @end
17
+
18
+ @implementation RNSecureUIView
19
+
20
+ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
21
+ if (self.isCopyPasteDisabled) {
22
+ return NO;
23
+ }
24
+ return [super canPerformAction:action withSender:sender];
25
+ }
26
+
27
+ @end
28
+
29
+ // ─────────────────────────────────────────────────────────────
30
+ // ViewManager — exposes RNSecureUIView to the Paper bridge
31
+ // ─────────────────────────────────────────────────────────────
32
+
33
+ @interface RNSecureViewManager : RCTViewManager
34
+ @end
35
+
36
+ @implementation RNSecureViewManager
37
+
38
+ RCT_EXPORT_MODULE(RNSecureView)
39
+
40
+ - (UIView *)view {
41
+ return [RNSecureUIView new];
42
+ }
43
+
44
+ RCT_CUSTOM_VIEW_PROPERTY(isCopyPasteDisabled, BOOL, RNSecureUIView) {
45
+ view.isCopyPasteDisabled = json ? [RCTConvert BOOL:json] : defaultView.isCopyPasteDisabled;
46
+ }
47
+
48
+ @end
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+
3
+ import { useState, useEffect, useCallback } from 'react';
4
+ import { disableScreenCapture, enableScreenCapture, isScreenBeingRecorded, enableAppSwitcherProtection, disableAppSwitcherProtection, clearClipboard, onScreenshotTaken, onScreenRecordingStarted, onScreenRecordingStopped } from "./PrivacyGuardkitApi.js";
5
+ // ─────────────────────────────────────────────────────────────
6
+ // usePrivacyGuard
7
+ // ─────────────────────────────────────────────────────────────
8
+
9
+ /**
10
+ * One-stop hook that wires up all privacy guard features declaratively.
11
+ *
12
+ * @example
13
+ * const { isRecording, disableScreenCapture } = usePrivacyGuard({
14
+ * disableScreenCapture: true,
15
+ * enableAppSwitcherProtection: true,
16
+ * });
17
+ */
18
+ export function usePrivacyGuard(config = {}) {
19
+ const [captureDisabled, setCaptureDisabled] = useState(false);
20
+ const [isRecording, setIsRecording] = useState(false);
21
+
22
+ // Apply config on mount
23
+ useEffect(() => {
24
+ if (config.disableScreenCapture) {
25
+ disableScreenCapture().then(() => setCaptureDisabled(true));
26
+ }
27
+ if (config.enableAppSwitcherProtection) {
28
+ enableAppSwitcherProtection();
29
+ }
30
+
31
+ // Bootstrap recording state
32
+ isScreenBeingRecorded().then(setIsRecording);
33
+
34
+ // Recording listeners
35
+ const stopStart = onScreenRecordingStarted(() => setIsRecording(true));
36
+ const stopStop = onScreenRecordingStopped(() => setIsRecording(false));
37
+ return () => {
38
+ if (config.disableScreenCapture) {
39
+ enableScreenCapture().then(() => setCaptureDisabled(false));
40
+ }
41
+ if (config.enableAppSwitcherProtection) {
42
+ disableAppSwitcherProtection();
43
+ }
44
+ stopStart();
45
+ stopStop();
46
+ };
47
+ // eslint-disable-next-line react-hooks/exhaustive-deps
48
+ }, []);
49
+ const handleDisableCapture = useCallback(async () => {
50
+ await disableScreenCapture();
51
+ setCaptureDisabled(true);
52
+ }, []);
53
+ const handleEnableCapture = useCallback(async () => {
54
+ await enableScreenCapture();
55
+ setCaptureDisabled(false);
56
+ }, []);
57
+ return {
58
+ isScreenCaptureDisabled: captureDisabled,
59
+ isRecording,
60
+ disableScreenCapture: handleDisableCapture,
61
+ enableScreenCapture: handleEnableCapture,
62
+ enableAppSwitcherProtection: async () => {
63
+ await enableAppSwitcherProtection();
64
+ },
65
+ disableAppSwitcherProtection: async () => {
66
+ await disableAppSwitcherProtection();
67
+ },
68
+ clearClipboard
69
+ };
70
+ }
71
+
72
+ // ─────────────────────────────────────────────────────────────
73
+ // useScreenshotListener
74
+ // ─────────────────────────────────────────────────────────────
75
+
76
+ /**
77
+ * Calls `onTaken` every time the user takes a screenshot.
78
+ *
79
+ * @example
80
+ * useScreenshotListener(() => {
81
+ * console.log('Screenshot detected!');
82
+ * });
83
+ */
84
+ export function useScreenshotListener(onTaken) {
85
+ useEffect(() => {
86
+ const remove = onScreenshotTaken(onTaken);
87
+ return remove;
88
+ }, [onTaken]);
89
+ }
90
+
91
+ // ─────────────────────────────────────────────────────────────
92
+ // useScreenRecording
93
+ // ─────────────────────────────────────────────────────────────
94
+
95
+ /**
96
+ * Reactive boolean — true while screen is being recorded.
97
+ *
98
+ * @example
99
+ * const isRecording = useScreenRecording();
100
+ * if (isRecording) return <BlurredScreen />;
101
+ */
102
+ export function useScreenRecording() {
103
+ const [isRecording, setIsRecording] = useState(false);
104
+ useEffect(() => {
105
+ isScreenBeingRecorded().then(setIsRecording);
106
+ const stopStart = onScreenRecordingStarted(({
107
+ isRecording: r
108
+ }) => setIsRecording(r));
109
+ const stopEnd = onScreenRecordingStopped(({
110
+ isRecording: r
111
+ }) => setIsRecording(r));
112
+ return () => {
113
+ stopStart();
114
+ stopEnd();
115
+ };
116
+ }, []);
117
+ return isRecording;
118
+ }
119
+ //# sourceMappingURL=Hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useState","useEffect","useCallback","disableScreenCapture","enableScreenCapture","isScreenBeingRecorded","enableAppSwitcherProtection","disableAppSwitcherProtection","clearClipboard","onScreenshotTaken","onScreenRecordingStarted","onScreenRecordingStopped","usePrivacyGuard","config","captureDisabled","setCaptureDisabled","isRecording","setIsRecording","then","stopStart","stopStop","handleDisableCapture","handleEnableCapture","isScreenCaptureDisabled","useScreenshotListener","onTaken","remove","useScreenRecording","r","stopEnd"],"sourceRoot":"../../src","sources":["Hooks.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ import { NativeModules, NativeEventEmitter } from 'react-native';
4
+ const {
5
+ PrivacyGuardKit
6
+ } = NativeModules;
7
+ if (!PrivacyGuardKit) {
8
+ throw new Error('[react-native-privacy-guard-kit] Native module not found. ' + 'Make sure you have linked the library and rebuilt the app.');
9
+ }
10
+ export const NativePrivacyGuardKit = PrivacyGuardKit;
11
+ export const PrivacyGuardKitEmitter = new NativeEventEmitter(PrivacyGuardKit);
12
+ //# sourceMappingURL=NativePrivacyGuardKit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["NativeModules","NativeEventEmitter","PrivacyGuardKit","Error","NativePrivacyGuardKit","PrivacyGuardKitEmitter"],"sourceRoot":"../../src","sources":["NativePrivacyGuardKit.ts"],"mappings":";;AAAA,SAASA,aAAa,EAAEC,kBAAkB,QAAQ,cAAc;AAEhE,MAAM;EAAEC;AAAgB,CAAC,GAAGF,aAAa;AAEzC,IAAI,CAACE,eAAe,EAAE;EACpB,MAAM,IAAIC,KAAK,CACb,4DAA4D,GAC1D,4DACJ,CAAC;AACH;AAEA,OAAO,MAAMC,qBAAqB,GAAGF,eAAe;AACpD,OAAO,MAAMG,sBAAsB,GAAG,IAAIJ,kBAAkB,CAACC,eAAe,CAAC","ignoreList":[]}
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+
3
+ import { createContext, useContext, useEffect, useState, useCallback } from 'react';
4
+ import { disableScreenCapture, enableScreenCapture, enableAppSwitcherProtection, disableAppSwitcherProtection, isScreenBeingRecorded, clearClipboard, onScreenRecordingStarted, onScreenRecordingStopped, onScreenshotTaken } from "./PrivacyGuardkitApi.js";
5
+
6
+ // ─────────────────────────────────────────────────────────────
7
+ // Context
8
+ // ─────────────────────────────────────────────────────────────
9
+ import { jsx as _jsx } from "react/jsx-runtime";
10
+ const PrivacyGuardContext = /*#__PURE__*/createContext(null);
11
+
12
+ // ─────────────────────────────────────────────────────────────
13
+ // Provider
14
+ // ─────────────────────────────────────────────────────────────
15
+
16
+ /**
17
+ * Wrap your root (or any sensitive screen) with this provider.
18
+ * All children can call `usePrivacyGuardContext()` to access the API.
19
+ *
20
+ * @example
21
+ * <PrivacyGuardProvider
22
+ * config={{ disableScreenCapture: true, enableAppSwitcherProtection: true }}
23
+ * onScreenshot={() => Alert.alert('Screenshot blocked!')}
24
+ * >
25
+ * <App />
26
+ * </PrivacyGuardProvider>
27
+ */
28
+ export function PrivacyGuardProvider({
29
+ children,
30
+ config = {},
31
+ onScreenshot
32
+ }) {
33
+ const [captureDisabled, setCaptureDisabled] = useState(false);
34
+ const [isRecording, setIsRecording] = useState(false);
35
+ useEffect(() => {
36
+ // Apply config
37
+ if (config.disableScreenCapture) {
38
+ disableScreenCapture().then(() => setCaptureDisabled(true));
39
+ }
40
+ if (config.enableAppSwitcherProtection) {
41
+ enableAppSwitcherProtection();
42
+ }
43
+ isScreenBeingRecorded().then(setIsRecording);
44
+
45
+ // Event subscriptions
46
+ const cleanups = [];
47
+ if (onScreenshot) {
48
+ cleanups.push(onScreenshotTaken(onScreenshot));
49
+ }
50
+ cleanups.push(onScreenRecordingStarted(() => setIsRecording(true)));
51
+ cleanups.push(onScreenRecordingStopped(() => setIsRecording(false)));
52
+ return () => {
53
+ cleanups.forEach(fn => fn());
54
+ if (config.disableScreenCapture) enableScreenCapture();
55
+ if (config.enableAppSwitcherProtection) disableAppSwitcherProtection();
56
+ };
57
+ // eslint-disable-next-line react-hooks/exhaustive-deps
58
+ }, []);
59
+ const handleDisable = useCallback(async () => {
60
+ await disableScreenCapture();
61
+ setCaptureDisabled(true);
62
+ }, []);
63
+ const handleEnable = useCallback(async () => {
64
+ await enableScreenCapture();
65
+ setCaptureDisabled(false);
66
+ }, []);
67
+ const value = {
68
+ isScreenCaptureDisabled: captureDisabled,
69
+ isRecording,
70
+ disableScreenCapture: handleDisable,
71
+ enableScreenCapture: handleEnable,
72
+ enableAppSwitcherProtection: async () => enableAppSwitcherProtection(),
73
+ disableAppSwitcherProtection: async () => disableAppSwitcherProtection(),
74
+ clearClipboard
75
+ };
76
+ return /*#__PURE__*/_jsx(PrivacyGuardContext.Provider, {
77
+ value: value,
78
+ children: children
79
+ });
80
+ }
81
+
82
+ // ─────────────────────────────────────────────────────────────
83
+ // Consumer hook
84
+ // ─────────────────────────────────────────────────────────────
85
+
86
+ /**
87
+ * Access the PrivacyGuard API from any component inside the provider.
88
+ *
89
+ * @example
90
+ * const { isRecording } = usePrivacyGuardContext();
91
+ */
92
+ export function usePrivacyGuardContext() {
93
+ const ctx = useContext(PrivacyGuardContext);
94
+ if (!ctx) {
95
+ throw new Error('usePrivacyGuardContext must be used inside <PrivacyGuardProvider>');
96
+ }
97
+ return ctx;
98
+ }
99
+ //# sourceMappingURL=PrivacyGuardProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["createContext","useContext","useEffect","useState","useCallback","disableScreenCapture","enableScreenCapture","enableAppSwitcherProtection","disableAppSwitcherProtection","isScreenBeingRecorded","clearClipboard","onScreenRecordingStarted","onScreenRecordingStopped","onScreenshotTaken","jsx","_jsx","PrivacyGuardContext","PrivacyGuardProvider","children","config","onScreenshot","captureDisabled","setCaptureDisabled","isRecording","setIsRecording","then","cleanups","push","forEach","fn","handleDisable","handleEnable","value","isScreenCaptureDisabled","Provider","usePrivacyGuardContext","ctx","Error"],"sourceRoot":"../../src","sources":["PrivacyGuardProvider.tsx"],"mappings":"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","ignoreList":[]}