123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import { EmitterSubscription, Platform } from "react-native";
  2. import * as RNGSModule from "./module";
  3. export { BackgroundBlurEffectIOS, Lang } from "./module";
  4. export interface IAPI1Result {
  5. success: 0 | 1;
  6. challenge: string;
  7. gt: string;
  8. new_captcha: boolean;
  9. [key: string]: any;
  10. }
  11. export interface IOption {
  12. // API1
  13. api1Result: IAPI1Result;
  14. // debug
  15. debug?: boolean;
  16. // view 加载超时时间,默认10000
  17. loadTimeout?: number;
  18. // 第二步向极验服务器发送请求超时时间,默认10000
  19. reqTimeout?: number;
  20. // 语言
  21. lang?: RNGSModule.Lang;
  22. // 点击背景是否可以取消验证
  23. enableBackgroundCancel?: boolean;
  24. // 背景色 IOS Only
  25. backgroundColorIOS?: any;
  26. // 背景模糊类型 IOS Only
  27. backgroundBlurEffectIOS?: RNGSModule.BackgroundBlurEffectIOS;
  28. // 事件监听
  29. onEvent?: (code: Events, data?: Array<number | string>) => void;
  30. }
  31. export interface IResult {
  32. geetest_challenge: string;
  33. geetest_seccode: string;
  34. geetest_validate: string;
  35. [key: string]: any;
  36. }
  37. export enum Errors {
  38. // 参数解析错误
  39. PARAMETER_PARSE_FAILED = -1,
  40. // 安卓 activity 已经销毁
  41. ANDROID_ACTIVITY_DESTROYED = -2,
  42. // 重复运行
  43. DUPLICATE_START = -3,
  44. }
  45. export enum Events {
  46. // 验证结果
  47. RESULT = 1,
  48. // 验证窗口关闭
  49. CLOSED = 2,
  50. // 验证失败
  51. FAILED = 3,
  52. // 发生错误
  53. ERROR = 0,
  54. }
  55. enum InternalStatus {
  56. None = 0b0,
  57. // 认证中
  58. Running = 0b1,
  59. // 停止认证中
  60. Stoping = 0b1 >> 1,
  61. }
  62. let internalStatus = InternalStatus.None;
  63. let eventListener: EmitterSubscription | null = null;
  64. const DEFAULT_OPTION = {
  65. api1Result: "",
  66. debug: false,
  67. loadTimeout: 10000,
  68. reqTimeout: 10000,
  69. lang: RNGSModule.Lang.System,
  70. enableBackgroundCancel: false,
  71. backgroundColorIOS: 0, // processColor('transparent')
  72. backgroundBlurEffectIOS: RNGSModule.BackgroundBlurEffectIOS.None,
  73. };
  74. // 进行行为认证
  75. export function start(option: IOption): Promise<IResult> {
  76. return new Promise((resolve, reject) => {
  77. if (internalStatus & InternalStatus.Running) {
  78. return reject(new GeetestError(
  79. Errors.DUPLICATE_START, "Duplicate start"));
  80. }
  81. internalStatus |= InternalStatus.Running;
  82. eventListener = RNGSModule.addListener(([code, ...data]) => {
  83. switch (code) {
  84. case Events.RESULT:
  85. resolve(JSON.parse(data[0]));
  86. stop();
  87. break;
  88. case Events.FAILED:
  89. reject(new Error('FAILED'));
  90. case Events.CLOSED:
  91. reject(new Error('CLOSED'));
  92. stop();
  93. break;
  94. case Events.ERROR:
  95. reject(new GeetestError(data[0], data[1]));
  96. stop();
  97. break;
  98. }
  99. if (typeof option.onEvent === "function") {
  100. option.onEvent(code, data);
  101. }
  102. });
  103. RNGSModule.start(RNGSModule.parseOption(option, DEFAULT_OPTION));
  104. });
  105. }
  106. function stop() {
  107. if (internalStatus & InternalStatus.Stoping) { return; }
  108. internalStatus |= InternalStatus.Stoping;
  109. RNGSModule.stop(() => {
  110. internalStatus = InternalStatus.None;
  111. if (eventListener && typeof eventListener.remove === "function") {
  112. eventListener.remove();
  113. eventListener = null;
  114. }
  115. });
  116. }
  117. export class GeetestError extends Error {
  118. constructor(readonly code: number, readonly message: string) {
  119. super(message);
  120. // @ts-ignore
  121. if (Error.captureStackTrace) {
  122. // @ts-ignore
  123. Error.captureStackTrace(this, GeetestError);
  124. }
  125. this.name = "GeetestError";
  126. }
  127. }