react-native-ovpn 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 (115) hide show
  1. package/LICENSE +20 -0
  2. package/Openvpn.podspec +34 -0
  3. package/README.md +80 -0
  4. package/android/build.gradle +98 -0
  5. package/android/libs/README.md +46 -0
  6. package/android/libs/ics-openvpn.aar +0 -0
  7. package/android/src/main/AndroidManifest.xml +54 -0
  8. package/android/src/main/java/com/openvpn/NotificationHelper.kt +59 -0
  9. package/android/src/main/java/com/openvpn/OpenvpnEventBus.kt +52 -0
  10. package/android/src/main/java/com/openvpn/OpenvpnException.kt +6 -0
  11. package/android/src/main/java/com/openvpn/OpenvpnModule.kt +140 -0
  12. package/android/src/main/java/com/openvpn/OpenvpnPackage.kt +31 -0
  13. package/android/src/main/java/com/openvpn/OpenvpnService.kt +248 -0
  14. package/android/src/main/java/com/openvpn/PermissionLauncher.kt +39 -0
  15. package/android/src/main/java/com/openvpn/ProfileBuilder.kt +68 -0
  16. package/android/src/main/res/drawable/ic_vpn_default.xml +10 -0
  17. package/android/src/main/res/values/strings.xml +6 -0
  18. package/android/src/test/java/com/openvpn/NotificationHelperTest.kt +49 -0
  19. package/android/src/test/java/com/openvpn/ProfileBuilderTest.kt +83 -0
  20. package/app.plugin.js +3 -0
  21. package/ios/Openvpn-Bridging-Header.h +8 -0
  22. package/ios/Openvpn.h +5 -0
  23. package/ios/Openvpn.mm +123 -0
  24. package/ios/OpenvpnAppGroup.swift +59 -0
  25. package/ios/OpenvpnConstants.swift +46 -0
  26. package/ios/OpenvpnEventBridge.swift +58 -0
  27. package/ios/OpenvpnManager.swift +219 -0
  28. package/ios/PacketTunnelProvider/Info.plist +31 -0
  29. package/ios/PacketTunnelProvider/PacketTunnelProvider.swift +199 -0
  30. package/ios/PacketTunnelProvider/README.md +106 -0
  31. package/lib/module/NativeOpenvpn.js +5 -0
  32. package/lib/module/NativeOpenvpn.js.map +1 -0
  33. package/lib/module/OpenVPNClient.js +185 -0
  34. package/lib/module/OpenVPNClient.js.map +1 -0
  35. package/lib/module/errors.js +13 -0
  36. package/lib/module/errors.js.map +1 -0
  37. package/lib/module/index.js +5 -0
  38. package/lib/module/index.js.map +1 -0
  39. package/lib/module/package.json +1 -0
  40. package/lib/module/reconnect.js +51 -0
  41. package/lib/module/reconnect.js.map +1 -0
  42. package/lib/module/types.js +2 -0
  43. package/lib/module/types.js.map +1 -0
  44. package/lib/typescript/package.json +1 -0
  45. package/lib/typescript/plugin/src/android/index.d.ts +5 -0
  46. package/lib/typescript/plugin/src/android/index.d.ts.map +1 -0
  47. package/lib/typescript/plugin/src/android/withAndroidAarCheck.d.ts +5 -0
  48. package/lib/typescript/plugin/src/android/withAndroidAarCheck.d.ts.map +1 -0
  49. package/lib/typescript/plugin/src/android/withAndroidLegacyPackaging.d.ts +5 -0
  50. package/lib/typescript/plugin/src/android/withAndroidLegacyPackaging.d.ts.map +1 -0
  51. package/lib/typescript/plugin/src/android/withAndroidMinSdk.d.ts +5 -0
  52. package/lib/typescript/plugin/src/android/withAndroidMinSdk.d.ts.map +1 -0
  53. package/lib/typescript/plugin/src/android/withAndroidNotificationIcon.d.ts +5 -0
  54. package/lib/typescript/plugin/src/android/withAndroidNotificationIcon.d.ts.map +1 -0
  55. package/lib/typescript/plugin/src/android/withAndroidPermissions.d.ts +5 -0
  56. package/lib/typescript/plugin/src/android/withAndroidPermissions.d.ts.map +1 -0
  57. package/lib/typescript/plugin/src/android/withAndroidService.d.ts +5 -0
  58. package/lib/typescript/plugin/src/android/withAndroidService.d.ts.map +1 -0
  59. package/lib/typescript/plugin/src/index.d.ts +6 -0
  60. package/lib/typescript/plugin/src/index.d.ts.map +1 -0
  61. package/lib/typescript/plugin/src/ios/index.d.ts +5 -0
  62. package/lib/typescript/plugin/src/ios/index.d.ts.map +1 -0
  63. package/lib/typescript/plugin/src/ios/withIosDeploymentTarget.d.ts +5 -0
  64. package/lib/typescript/plugin/src/ios/withIosDeploymentTarget.d.ts.map +1 -0
  65. package/lib/typescript/plugin/src/ios/withIosEntitlements.d.ts +5 -0
  66. package/lib/typescript/plugin/src/ios/withIosEntitlements.d.ts.map +1 -0
  67. package/lib/typescript/plugin/src/ios/withIosInfoPlist.d.ts +5 -0
  68. package/lib/typescript/plugin/src/ios/withIosInfoPlist.d.ts.map +1 -0
  69. package/lib/typescript/plugin/src/types.d.ts +14 -0
  70. package/lib/typescript/plugin/src/types.d.ts.map +1 -0
  71. package/lib/typescript/src/NativeOpenvpn.d.ts +41 -0
  72. package/lib/typescript/src/NativeOpenvpn.d.ts.map +1 -0
  73. package/lib/typescript/src/OpenVPNClient.d.ts +37 -0
  74. package/lib/typescript/src/OpenVPNClient.d.ts.map +1 -0
  75. package/lib/typescript/src/errors.d.ts +9 -0
  76. package/lib/typescript/src/errors.d.ts.map +1 -0
  77. package/lib/typescript/src/index.d.ts +5 -0
  78. package/lib/typescript/src/index.d.ts.map +1 -0
  79. package/lib/typescript/src/reconnect.d.ts +23 -0
  80. package/lib/typescript/src/reconnect.d.ts.map +1 -0
  81. package/lib/typescript/src/types.d.ts +41 -0
  82. package/lib/typescript/src/types.d.ts.map +1 -0
  83. package/package.json +193 -0
  84. package/plugin/build/android/index.d.ts +4 -0
  85. package/plugin/build/android/index.js +24 -0
  86. package/plugin/build/android/withAndroidAarCheck.d.ts +4 -0
  87. package/plugin/build/android/withAndroidAarCheck.js +60 -0
  88. package/plugin/build/android/withAndroidLegacyPackaging.d.ts +4 -0
  89. package/plugin/build/android/withAndroidLegacyPackaging.js +18 -0
  90. package/plugin/build/android/withAndroidMinSdk.d.ts +4 -0
  91. package/plugin/build/android/withAndroidMinSdk.js +13 -0
  92. package/plugin/build/android/withAndroidNotificationIcon.d.ts +4 -0
  93. package/plugin/build/android/withAndroidNotificationIcon.js +64 -0
  94. package/plugin/build/android/withAndroidPermissions.d.ts +4 -0
  95. package/plugin/build/android/withAndroidPermissions.js +30 -0
  96. package/plugin/build/android/withAndroidService.d.ts +4 -0
  97. package/plugin/build/android/withAndroidService.js +40 -0
  98. package/plugin/build/index.d.ts +5 -0
  99. package/plugin/build/index.js +18 -0
  100. package/plugin/build/ios/index.d.ts +4 -0
  101. package/plugin/build/ios/index.js +15 -0
  102. package/plugin/build/ios/withIosDeploymentTarget.d.ts +4 -0
  103. package/plugin/build/ios/withIosDeploymentTarget.js +28 -0
  104. package/plugin/build/ios/withIosEntitlements.d.ts +4 -0
  105. package/plugin/build/ios/withIosEntitlements.js +15 -0
  106. package/plugin/build/ios/withIosInfoPlist.d.ts +4 -0
  107. package/plugin/build/ios/withIosInfoPlist.js +14 -0
  108. package/plugin/build/types.d.ts +13 -0
  109. package/plugin/build/types.js +2 -0
  110. package/src/NativeOpenvpn.ts +46 -0
  111. package/src/OpenVPNClient.ts +239 -0
  112. package/src/errors.ts +29 -0
  113. package/src/index.ts +12 -0
  114. package/src/reconnect.ts +68 -0
  115. package/src/types.ts +53 -0
@@ -0,0 +1,37 @@
1
+ import type { Stats, Status, VPNState } from './types';
2
+ import { OpenVPNError } from './errors';
3
+ import type { ConnectOptions, ReconnectingEvent } from './types';
4
+ type Listener<T> = (payload: T) => void;
5
+ type EventMap = {
6
+ state: VPNState;
7
+ stats: Stats;
8
+ log: string;
9
+ error: OpenVPNError;
10
+ reconnecting: ReconnectingEvent;
11
+ };
12
+ export declare class OpenVPNClient {
13
+ private readonly emitter;
14
+ private readonly listeners;
15
+ private subscriptions;
16
+ private currentConnect;
17
+ private userRequestedDisconnect;
18
+ private hardErrorPending;
19
+ private scheduler;
20
+ private lastParams;
21
+ private lastReconnectOpts;
22
+ constructor();
23
+ on<K extends keyof EventMap>(event: K, fn: Listener<EventMap[K]>): void;
24
+ off<K extends keyof EventMap>(event: K, fn: Listener<EventMap[K]>): void;
25
+ removeAllListeners(): void;
26
+ protected emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): void;
27
+ dispose(): void;
28
+ requestPermission(): Promise<boolean>;
29
+ getStatus(): Promise<Status>;
30
+ getStats(): Promise<Stats>;
31
+ connect(options: ConnectOptions): Promise<void>;
32
+ disconnect(): Promise<void>;
33
+ private settleConnect;
34
+ private handleDisconnect;
35
+ }
36
+ export {};
37
+ //# sourceMappingURL=OpenVPNClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpenVPNClient.d.ts","sourceRoot":"","sources":["../../../src/OpenVPNClient.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACvD,OAAO,EAAiC,YAAY,EAAE,MAAM,UAAU,CAAC;AAEvE,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAIjE,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,CAAC;AAExC,KAAK,QAAQ,GAAG;IACd,KAAK,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,YAAY,CAAC;IACpB,YAAY,EAAE,iBAAiB,CAAC;CACjC,CAAC;AASF,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAQxB;IACF,OAAO,CAAC,aAAa,CAA6B;IAElD,OAAO,CAAC,cAAc,CAGN;IAEhB,OAAO,CAAC,uBAAuB,CAAS;IACxC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,iBAAiB,CAIvB;;IA+CF,EAAE,CAAC,CAAC,SAAS,MAAM,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAIvE,GAAG,CAAC,CAAC,SAAS,MAAM,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAIxE,kBAAkB,IAAI,IAAI;IAM1B,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,MAAM,QAAQ,EACrC,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,GACnB,IAAI;IAIP,OAAO,IAAI,IAAI;IAMT,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC;IAIrC,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAK5B,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC;IAI1B,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA2C/C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IASjC,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,gBAAgB;CAsCzB"}
@@ -0,0 +1,9 @@
1
+ export declare const ERROR_CODES: readonly ["PERMISSION_DENIED", "INVALID_CONFIG", "AUTH_FAILED", "TLS_FAILED", "NETWORK_UNREACHABLE", "RECONNECT_EXHAUSTED", "NATIVE_ERROR"];
2
+ export type ErrorCode = (typeof ERROR_CODES)[number];
3
+ export declare class OpenVPNError extends Error {
4
+ readonly code: ErrorCode;
5
+ readonly nativeMessage?: string;
6
+ constructor(code: ErrorCode, nativeMessage?: string);
7
+ }
8
+ export declare const HARD_ERROR_CODES: ReadonlySet<ErrorCode>;
9
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/errors.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,6IAQd,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;gBAEpB,IAAI,EAAE,SAAS,EAAE,aAAa,CAAC,EAAE,MAAM;CAMpD;AAED,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,SAAS,CAIlD,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { OpenVPNClient } from './OpenVPNClient';
2
+ export { OpenVPNError, ERROR_CODES } from './errors';
3
+ export type { ErrorCode } from './errors';
4
+ export type { VPNState, ConnectOptions, ReconnectOptions, NotificationOptions, Status, Stats, ReconnectingEvent, } from './types';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACrD,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,YAAY,EACV,QAAQ,EACR,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,MAAM,EACN,KAAK,EACL,iBAAiB,GAClB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,23 @@
1
+ export declare function calculateDelay(attempt: number, baseDelayMs: number, maxDelayMs: number): number;
2
+ export type SchedulerOptions = {
3
+ maxRetries: number;
4
+ baseDelayMs: number;
5
+ maxDelayMs: number;
6
+ onAttempt: (info: {
7
+ attempt: number;
8
+ delayMs: number;
9
+ }) => void;
10
+ onExhausted: () => void;
11
+ };
12
+ export declare class Scheduler {
13
+ private readonly opts;
14
+ private attempt;
15
+ private timer;
16
+ private started;
17
+ constructor(opts: SchedulerOptions);
18
+ start(): void;
19
+ stop(): void;
20
+ notifyFailure(): void;
21
+ private scheduleNext;
22
+ }
23
+ //# sourceMappingURL=reconnect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconnect.d.ts","sourceRoot":"","sources":["../../../src/reconnect.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,MAAM,CAGR;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAChE,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmB;IACxC,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,KAAK,CAA8C;IAC3D,OAAO,CAAC,OAAO,CAAS;gBAEZ,IAAI,EAAE,gBAAgB;IAIlC,KAAK,IAAI,IAAI;IAOb,IAAI,IAAI,IAAI;IAQZ,aAAa,IAAI,IAAI;IAUrB,OAAO,CAAC,YAAY;CAerB"}
@@ -0,0 +1,41 @@
1
+ export type VPNState = 'idle' | 'connecting' | 'reconnecting' | 'connected' | 'disconnecting' | 'disconnected' | 'error';
2
+ export type NotificationOptions = {
3
+ title?: string;
4
+ text?: string;
5
+ smallIcon?: string;
6
+ channelId?: string;
7
+ };
8
+ export type ReconnectOptions = {
9
+ maxRetries?: number;
10
+ baseDelayMs?: number;
11
+ maxDelayMs?: number;
12
+ };
13
+ export type ConnectOptions = {
14
+ config: string;
15
+ username: string;
16
+ password: string;
17
+ reconnect?: ReconnectOptions;
18
+ killSwitch?: boolean;
19
+ dns?: string[];
20
+ allowedApps?: string[];
21
+ disallowedApps?: string[];
22
+ notification?: NotificationOptions;
23
+ };
24
+ export type Status = {
25
+ state: VPNState;
26
+ connectedSince?: number;
27
+ server?: string;
28
+ localIp?: string;
29
+ remoteIp?: string;
30
+ };
31
+ export type Stats = {
32
+ bytesIn: number;
33
+ bytesOut: number;
34
+ durationMs: number;
35
+ };
36
+ export type ReconnectingEvent = {
37
+ attempt: number;
38
+ /** Delay in ms that elapsed BEFORE this attempt was made (not the next wait). */
39
+ delayMs: number;
40
+ };
41
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAChB,MAAM,GACN,YAAY,GACZ,cAAc,GACd,WAAW,GACX,eAAe,GACf,cAAc,GACd,OAAO,CAAC;AAEZ,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,KAAK,EAAE,QAAQ,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,193 @@
1
+ {
2
+ "name": "react-native-ovpn",
3
+ "version": "0.1.0",
4
+ "description": "OpenVPN client for React Native — Android, iOS, and Expo. New Architecture (TurboModule), kill switch, custom DNS, bounded auto-reconnect.",
5
+ "main": "./lib/module/index.js",
6
+ "types": "./lib/typescript/src/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "source": "./src/index.ts",
10
+ "types": "./lib/typescript/src/index.d.ts",
11
+ "default": "./lib/module/index.js"
12
+ },
13
+ "./app.plugin": "./app.plugin.js",
14
+ "./app.plugin.js": "./app.plugin.js",
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "src",
19
+ "lib",
20
+ "plugin/build",
21
+ "app.plugin.js",
22
+ "android",
23
+ "ios",
24
+ "cpp",
25
+ "*.podspec",
26
+ "react-native.config.js",
27
+ "!ios/build",
28
+ "!android/build",
29
+ "!android/gradle",
30
+ "!android/gradlew",
31
+ "!android/gradlew.bat",
32
+ "!android/local.properties",
33
+ "!**/__tests__",
34
+ "!**/__fixtures__",
35
+ "!**/__mocks__",
36
+ "!**/.*"
37
+ ],
38
+ "scripts": {
39
+ "example": "yarn workspace react-native-openvpn-example",
40
+ "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
41
+ "prepare:plugin": "tsc -p plugin/tsconfig.json",
42
+ "prepare": "bob build && tsc -p plugin/tsconfig.json",
43
+ "typecheck": "tsc",
44
+ "lint": "eslint \"**/*.{js,ts,tsx}\"",
45
+ "test": "jest"
46
+ },
47
+ "keywords": [
48
+ "react-native",
49
+ "expo",
50
+ "ios",
51
+ "android",
52
+ "vpn",
53
+ "openvpn",
54
+ "ovpn",
55
+ "tunnel",
56
+ "kill-switch",
57
+ "turbo-module",
58
+ "new-architecture",
59
+ "fabric"
60
+ ],
61
+ "engines": {
62
+ "node": ">=18"
63
+ },
64
+ "repository": {
65
+ "type": "git",
66
+ "url": "git+https://github.com/Raselj71/react-native-ovpn.git"
67
+ },
68
+ "author": "Rasel <rasel.cse.green@gmail.com> (https://github.com/Raselj71)",
69
+ "license": "MIT",
70
+ "bugs": {
71
+ "url": "https://github.com/Raselj71/react-native-ovpn/issues"
72
+ },
73
+ "homepage": "https://github.com/Raselj71/react-native-ovpn#readme",
74
+ "publishConfig": {
75
+ "registry": "https://registry.npmjs.org/"
76
+ },
77
+ "devDependencies": {
78
+ "@eslint/compat": "^2.0.3",
79
+ "@eslint/eslintrc": "^3.3.5",
80
+ "@eslint/js": "^10.0.1",
81
+ "@expo/config-plugins": "9.0.0",
82
+ "@react-native/babel-preset": "0.85.0",
83
+ "@react-native/eslint-config": "0.85.0",
84
+ "@react-native/jest-preset": "0.85.0",
85
+ "@types/jest": "^29.5.14",
86
+ "@types/node": "22.0.0",
87
+ "@types/react": "^19.2.0",
88
+ "del-cli": "^7.0.0",
89
+ "eslint": "^9.39.4",
90
+ "eslint-config-prettier": "^10.1.8",
91
+ "eslint-plugin-ft-flow": "^3.0.11",
92
+ "eslint-plugin-prettier": "^5.5.5",
93
+ "jest": "^29.7.0",
94
+ "prettier": "^3.8.1",
95
+ "react": "19.2.3",
96
+ "react-native": "0.85.0",
97
+ "react-native-builder-bob": "^0.41.0",
98
+ "ts-jest": "29.0.0",
99
+ "turbo": "^2.8.21",
100
+ "typescript": "^6.0.2"
101
+ },
102
+ "peerDependencies": {
103
+ "react": "*",
104
+ "react-native": "*"
105
+ },
106
+ "workspaces": [
107
+ "example"
108
+ ],
109
+ "packageManager": "yarn@4.11.0",
110
+ "react-native-builder-bob": {
111
+ "source": "src",
112
+ "output": "lib",
113
+ "targets": [
114
+ [
115
+ "module",
116
+ {
117
+ "esm": true
118
+ }
119
+ ],
120
+ [
121
+ "typescript",
122
+ {
123
+ "project": "tsconfig.build.json"
124
+ }
125
+ ]
126
+ ]
127
+ },
128
+ "codegenConfig": {
129
+ "name": "OpenvpnSpec",
130
+ "type": "modules",
131
+ "jsSrcsDir": "src",
132
+ "android": {
133
+ "javaPackageName": "com.openvpn"
134
+ }
135
+ },
136
+ "prettier": {
137
+ "quoteProps": "consistent",
138
+ "singleQuote": true,
139
+ "tabWidth": 2,
140
+ "trailingComma": "es5",
141
+ "useTabs": false
142
+ },
143
+ "jest": {
144
+ "preset": "@react-native/jest-preset",
145
+ "modulePathIgnorePatterns": [
146
+ "<rootDir>/example/node_modules",
147
+ "<rootDir>/lib/",
148
+ "<rootDir>/plugin/build/"
149
+ ],
150
+ "automock": false,
151
+ "setupFilesAfterEnv": [
152
+ "<rootDir>/jest.setup.js"
153
+ ],
154
+ "moduleNameMapper": {
155
+ "^.+/NativeOpenvpn$": "<rootDir>/__mocks__/NativeOpenvpn.ts"
156
+ },
157
+ "collectCoverageFrom": [
158
+ "src/**/*.ts",
159
+ "plugin/src/**/*.ts",
160
+ "!src/NativeOpenvpn.ts",
161
+ "!src/index.ts",
162
+ "!src/types.ts",
163
+ "!src/**/__tests__/**",
164
+ "!plugin/src/**/__tests__/**"
165
+ ],
166
+ "coverageThreshold": {
167
+ "global": {
168
+ "branches": 80,
169
+ "functions": 85,
170
+ "lines": 85,
171
+ "statements": 85
172
+ }
173
+ },
174
+ "transform": {
175
+ "^.+\\.(ts|tsx)$": [
176
+ "ts-jest",
177
+ {
178
+ "tsconfig": "<rootDir>/plugin/tsconfig.json",
179
+ "isolatedModules": true,
180
+ "diagnostics": false
181
+ }
182
+ ]
183
+ }
184
+ },
185
+ "create-react-native-library": {
186
+ "type": "turbo-module",
187
+ "languages": "kotlin-objc",
188
+ "tools": [
189
+ "eslint"
190
+ ],
191
+ "version": "0.62.0"
192
+ }
193
+ }
@@ -0,0 +1,4 @@
1
+ import type { ConfigPlugin } from '@expo/config-plugins';
2
+ import type { OpenVPNPluginProps } from '../types';
3
+ declare const withOpenVPNAndroid: ConfigPlugin<OpenVPNPluginProps>;
4
+ export default withOpenVPNAndroid;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const withAndroidPermissions_1 = __importDefault(require("./withAndroidPermissions"));
7
+ const withAndroidService_1 = __importDefault(require("./withAndroidService"));
8
+ const withAndroidMinSdk_1 = __importDefault(require("./withAndroidMinSdk"));
9
+ const withAndroidNotificationIcon_1 = __importDefault(require("./withAndroidNotificationIcon"));
10
+ const withAndroidLegacyPackaging_1 = __importDefault(require("./withAndroidLegacyPackaging"));
11
+ const withAndroidAarCheck_1 = __importDefault(require("./withAndroidAarCheck"));
12
+ const withOpenVPNAndroid = (config, props) => {
13
+ config = (0, withAndroidPermissions_1.default)(config, props);
14
+ config = (0, withAndroidService_1.default)(config, props);
15
+ config = (0, withAndroidMinSdk_1.default)(config, props);
16
+ config = (0, withAndroidNotificationIcon_1.default)(config, props);
17
+ // Required so the openvpn executable in jniLibs is extracted to disk
18
+ // (it's launched via Runtime.exec, not loaded as a .so).
19
+ config = (0, withAndroidLegacyPackaging_1.default)(config, props);
20
+ // AAR check last — let other Android errors surface first.
21
+ config = (0, withAndroidAarCheck_1.default)(config, props);
22
+ return config;
23
+ };
24
+ exports.default = withOpenVPNAndroid;
@@ -0,0 +1,4 @@
1
+ import { type ConfigPlugin } from '@expo/config-plugins';
2
+ import type { OpenVPNPluginProps } from '../types';
3
+ declare const withAndroidAarCheck: ConfigPlugin<OpenVPNPluginProps>;
4
+ export default withAndroidAarCheck;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const config_plugins_1 = require("@expo/config-plugins");
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const AAR_RELATIVE = path.join('node_modules', 'react-native-ovpn', 'android', 'libs', 'ics-openvpn.aar');
40
+ const withAndroidAarCheck = (config) => {
41
+ return (0, config_plugins_1.withDangerousMod)(config, [
42
+ 'android',
43
+ async (config) => {
44
+ const projectRoot = config.modRequest.projectRoot;
45
+ const aarPath = path.join(projectRoot, AAR_RELATIVE);
46
+ if (!fs.existsSync(aarPath)) {
47
+ throw new Error('react-native-ovpn: ics-openvpn AAR is missing at\n' +
48
+ ' ' +
49
+ aarPath +
50
+ '\n\n' +
51
+ 'Run the build script once before `expo prebuild`:\n' +
52
+ ' ./scripts/build-ics-openvpn-aar.sh (macOS/Linux)\n' +
53
+ ' pwsh scripts/build-ics-openvpn-aar.ps1 (Windows)\n\n' +
54
+ 'See node_modules/react-native-ovpn/android/libs/README.md for prerequisites.');
55
+ }
56
+ return config;
57
+ },
58
+ ]);
59
+ };
60
+ exports.default = withAndroidAarCheck;
@@ -0,0 +1,4 @@
1
+ import type { ConfigPlugin } from '@expo/config-plugins';
2
+ import type { OpenVPNPluginProps } from '../types';
3
+ declare const withAndroidLegacyPackaging: ConfigPlugin<OpenVPNPluginProps>;
4
+ export default withAndroidLegacyPackaging;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const config_plugins_1 = require("@expo/config-plugins");
4
+ const KEY = 'expo.useLegacyPackaging';
5
+ const withAndroidLegacyPackaging = (config, _props) => {
6
+ return (0, config_plugins_1.withGradleProperties)(config, (cfg) => {
7
+ const items = cfg.modResults;
8
+ const existing = items.find((item) => item.type === 'property' && item.key === KEY);
9
+ if (existing) {
10
+ existing.value = 'true';
11
+ }
12
+ else {
13
+ items.push({ type: 'property', key: KEY, value: 'true' });
14
+ }
15
+ return cfg;
16
+ });
17
+ };
18
+ exports.default = withAndroidLegacyPackaging;
@@ -0,0 +1,4 @@
1
+ import type { ConfigPlugin } from '@expo/config-plugins';
2
+ import type { OpenVPNPluginProps } from '../types';
3
+ declare const _default: ConfigPlugin<OpenVPNPluginProps>;
4
+ export default _default;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const REQUIRED_MIN_SDK = 24;
4
+ function withAndroidMinSdk(config, _props) {
5
+ if (!config.android)
6
+ config.android = {};
7
+ const current = config.android.minSdkVersion;
8
+ if (typeof current !== 'number' || current < REQUIRED_MIN_SDK) {
9
+ config.android.minSdkVersion = REQUIRED_MIN_SDK;
10
+ }
11
+ return config;
12
+ }
13
+ exports.default = withAndroidMinSdk;
@@ -0,0 +1,4 @@
1
+ import { type ConfigPlugin } from '@expo/config-plugins';
2
+ import type { OpenVPNPluginProps } from '../types';
3
+ declare const withAndroidNotificationIcon: ConfigPlugin<OpenVPNPluginProps>;
4
+ export default withAndroidNotificationIcon;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const config_plugins_1 = require("@expo/config-plugins");
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const withAndroidNotificationIcon = (config, props) => {
40
+ if (!props.androidNotificationIcon)
41
+ return config;
42
+ const iconPath = props.androidNotificationIcon;
43
+ return (0, config_plugins_1.withDangerousMod)(config, [
44
+ 'android',
45
+ async (config) => {
46
+ const projectRoot = config.modRequest.projectRoot;
47
+ const platformRoot = config.modRequest.platformProjectRoot;
48
+ const absoluteSource = path.isAbsolute(iconPath)
49
+ ? iconPath
50
+ : path.resolve(projectRoot, iconPath);
51
+ if (!fs.existsSync(absoluteSource)) {
52
+ console.warn(`react-native-ovpn: androidNotificationIcon "${iconPath}" not found at ${absoluteSource}; skipping copy.`);
53
+ return config;
54
+ }
55
+ const ext = path.extname(absoluteSource) || '.png';
56
+ const destDir = path.join(platformRoot, 'app/src/main/res/drawable');
57
+ fs.mkdirSync(destDir, { recursive: true });
58
+ const destPath = path.join(destDir, `openvpn_notification${ext}`);
59
+ fs.copyFileSync(absoluteSource, destPath);
60
+ return config;
61
+ },
62
+ ]);
63
+ };
64
+ exports.default = withAndroidNotificationIcon;
@@ -0,0 +1,4 @@
1
+ import { type ConfigPlugin } from '@expo/config-plugins';
2
+ import type { OpenVPNPluginProps } from '../types';
3
+ declare const withAndroidPermissions: ConfigPlugin<OpenVPNPluginProps>;
4
+ export default withAndroidPermissions;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const config_plugins_1 = require("@expo/config-plugins");
4
+ const REQUIRED_PERMISSIONS = [
5
+ 'android.permission.INTERNET',
6
+ 'android.permission.ACCESS_NETWORK_STATE',
7
+ 'android.permission.FOREGROUND_SERVICE',
8
+ 'android.permission.FOREGROUND_SERVICE_SPECIAL_USE',
9
+ 'android.permission.POST_NOTIFICATIONS',
10
+ ];
11
+ const withAndroidPermissions = (config) => {
12
+ return (0, config_plugins_1.withAndroidManifest)(config, async (config) => {
13
+ const manifest = config.modResults.manifest;
14
+ if (!manifest['uses-permission']) {
15
+ manifest['uses-permission'] = [];
16
+ }
17
+ const existing = new Set(manifest['uses-permission']
18
+ .map((p) => p.$?.['android:name'])
19
+ .filter(Boolean));
20
+ for (const perm of REQUIRED_PERMISSIONS) {
21
+ if (existing.has(perm))
22
+ continue;
23
+ manifest['uses-permission'].push({
24
+ $: { 'android:name': perm },
25
+ });
26
+ }
27
+ return config;
28
+ });
29
+ };
30
+ exports.default = withAndroidPermissions;
@@ -0,0 +1,4 @@
1
+ import { type ConfigPlugin } from '@expo/config-plugins';
2
+ import type { OpenVPNPluginProps } from '../types';
3
+ declare const withAndroidService: ConfigPlugin<OpenVPNPluginProps>;
4
+ export default withAndroidService;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const config_plugins_1 = require("@expo/config-plugins");
4
+ const SERVICE_NAME = 'com.openvpn.OpenvpnService';
5
+ const withAndroidService = (config) => {
6
+ return (0, config_plugins_1.withAndroidManifest)(config, async (config) => {
7
+ const application = config.modResults.manifest.application?.[0];
8
+ if (!application)
9
+ return config;
10
+ if (!Array.isArray(application.service)) {
11
+ application.service = [];
12
+ }
13
+ const existing = application.service.find((s) => s.$?.['android:name'] === SERVICE_NAME);
14
+ if (existing)
15
+ return config;
16
+ application.service.push({
17
+ '$': {
18
+ 'android:name': SERVICE_NAME,
19
+ 'android:permission': 'android.permission.BIND_VPN_SERVICE',
20
+ 'android:foregroundServiceType': 'specialUse',
21
+ 'android:exported': 'false',
22
+ },
23
+ 'property': [
24
+ {
25
+ $: {
26
+ 'android:name': 'android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE',
27
+ 'android:value': 'vpn',
28
+ },
29
+ },
30
+ ],
31
+ 'intent-filter': [
32
+ {
33
+ action: [{ $: { 'android:name': 'android.net.VpnService' } }],
34
+ },
35
+ ],
36
+ });
37
+ return config;
38
+ });
39
+ };
40
+ exports.default = withAndroidService;
@@ -0,0 +1,5 @@
1
+ import type { ConfigPlugin } from '@expo/config-plugins';
2
+ import type { OpenVPNPluginProps } from './types';
3
+ declare const withOpenVPN: ConfigPlugin<OpenVPNPluginProps>;
4
+ export default withOpenVPN;
5
+ export type { OpenVPNPluginProps } from './types';