api.js 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. import { NativeEventEmitter, NativeModules, Platform } from 'react-native'
  2. import processColor from './lib/processColor'
  3. import validUrl from './lib/validUrl'
  4. import validCaptchaParams from './lib/validCaptchaParams'
  5. import invariant from 'invariant'
  6. import { EVENT_TYPE, ERROR_TYPE } from './constant'
  7. const { GeetestSensebot } = NativeModules
  8. const GSConfig = {
  9. api1: null,
  10. api2: null,
  11. maskColor: processColor('transparent'),
  12. isDebug: false
  13. }
  14. /**
  15. * configApi 配置 api 地址
  16. * @param {String} api1
  17. * @param {String} api2
  18. * @return {void}
  19. */
  20. export const configApi = (api1, api2) => {
  21. validUrl(api1)
  22. GSConfig.api1 = api1
  23. validUrl(api2)
  24. GSConfig.api2 = api2
  25. }
  26. /**
  27. * setMaskColor 配置行为验证背景遮罩颜色 iosOnly
  28. * @param {String} color
  29. * @return {void}
  30. */
  31. export const setMaskColor = color => {
  32. if (Platform.OS !== 'ios') return // 避免不必要的计算
  33. GSConfig.maskColor = processColor(color)
  34. }
  35. /**
  36. * enableDebug 开启调试 iosOnly
  37. * @param {Boolean} isDebug
  38. * @return {void}
  39. */
  40. export const enableDebug = isDebug => {
  41. GSConfig.isDebug = !!isDebug
  42. }
  43. /**
  44. * captcha 行为验证
  45. */
  46. export const captcha = async argument => {
  47. invariant(
  48. GSConfig.api1 !== null && GSConfig.api2 !== null,
  49. 'api address must be set, please run configApi function first.'
  50. )
  51. const {
  52. api1ReqReplacer, api1RespHandler,
  53. api2ReqReplacer, api2RespHandler
  54. } = argument || {}
  55. let payload = null
  56. let errCode = null
  57. let errMsg = null
  58. // initial captcha manager
  59. await GeetestSensebot.initCaptchaMgr(GSConfig.maskColor, GSConfig.isDebug)
  60. // api1 request
  61. let api1Resp = null
  62. let captchaParams = null
  63. try {
  64. let api1Req = new Request(GSConfig.api1, {
  65. method: 'GET',
  66. headers: { 'Content-Type': 'application/json' },
  67. credentials: 'include'
  68. })
  69. if (typeof api1ReqReplacer === 'function') {
  70. api1Req = await api1ReqReplacer(api2Req)
  71. if (!(api1Req instanceof Request)) {
  72. throw Error('api1ReqReplacer return value not a valid request object')
  73. }
  74. }
  75. api1Resp = await fetch(api1Req)
  76. } catch (e) {
  77. throw new GSError({
  78. errCode: ERROR_TYPE.API1,
  79. errMsg: `api1 request failed, ${e.message}`
  80. })
  81. }
  82. // api1 resp handle
  83. if (typeof api1RespHandler === 'function') {
  84. captchaParams = await api1RespHandler(api1Resp)
  85. } else {
  86. captchaParams = await defaultApi1RespHandler(api1Resp)
  87. }
  88. // captcha
  89. try {
  90. validCaptchaParams(captchaParams)
  91. } catch (e) {
  92. throw new GSError({
  93. errCode: ERROR_TYPE.CAPTCHA,
  94. errMsg: `captcha params error, ${e.message}`
  95. })
  96. }
  97. const capcataStartRes = await GeetestSensebot.captcha(
  98. captchaParams.success,
  99. captchaParams.gt,
  100. captchaParams.challenge,
  101. GSConfig.api2
  102. )
  103. if (!capcataStartRes) {
  104. throw new GSError({
  105. errCode: ERROR_TYPE.CAPTCHA,
  106. errMsg: 'captcha start failed, can\'t find captcha manager.'
  107. })
  108. }
  109. const captchaRes = await rnGSEventListener(EVENT_TYPE.CAPTCHA)
  110. payload = captchaRes.payload
  111. errCode = captchaRes.errCode
  112. errMsg = captchaRes.errMsg
  113. if (errCode) {
  114. throw new GSError({ errCode: ERROR_TYPE.CAPTCHA, errMsg })
  115. }
  116. // from sdk @param code 验证交互结果, 0失败/1成功
  117. if (payload.code !== '1') {
  118. throw new GSError({
  119. errCode: ERROR_TYPE.CAPTCHA,
  120. errMsg: `captcha valid failed, ${payload.message}`
  121. })
  122. }
  123. // api2 request
  124. // @param { geetest_challenge: "", geetest_seccode: "", geetest_validate: "" }
  125. const api2ReqParams = payload.result
  126. let api2Resp = null
  127. try {
  128. let api2Req = new Request(GSConfig.api2, {
  129. method: 'POST',
  130. headers: { 'Content-Type': 'application/json' },
  131. credentials: 'include',
  132. body: JSON.stringify(api2ReqParams)
  133. })
  134. if (typeof api2ReqReplacer === 'function') {
  135. api2Req = await api2ReqReplacer(api2Req)
  136. if (!(api2Req instanceof Request)) {
  137. throw Error('second params not a valid request object')
  138. }
  139. }
  140. api2Resp = await fetch(api2Req)
  141. } catch (e) {
  142. throw new GSError({
  143. errCode: EVENT_TYPE.API2,
  144. errMsg: `api2 request failed, ${e.message}`
  145. })
  146. }
  147. // clean
  148. stopCaptcha()
  149. // api2 resp handle
  150. if (typeof api2RespHandler === 'function') {
  151. return api2RespHandler(api2Resp)
  152. } else {
  153. return defaultApi2RespHandler(api2Resp)
  154. }
  155. }
  156. /**
  157. * stopCaptcha 停止行为验证
  158. */
  159. const stopCaptcha = () => {
  160. return GeetestSensebot.stopCaptcha()
  161. }
  162. /* event handle */
  163. const GSEmitter = new NativeEventEmitter(GeetestSensebot)
  164. const rnGSEventListener = listenEventType => {
  165. return new Promise(resolve => {
  166. let subscription = null
  167. const handleGSEvent = ({ type, ...otherParams }) => {
  168. if (type === EVENT_TYPE.ERROR) {
  169. resolve(otherParams)
  170. return
  171. }
  172. if (listenEventType !== type) return
  173. clearSubscribe()
  174. resolve(otherParams)
  175. }
  176. const clearSubscribe = () => {
  177. subscription.remove()
  178. }
  179. subscription = GSEmitter.addListener('RNGeetestSensebotEvent', handleGSEvent)
  180. })
  181. }
  182. /* event handle end */
  183. /* default captcha funcs */
  184. const defaultApi1RespHandler = async api1Resp => {
  185. /**
  186. * api1 官方示例接口
  187. * http://www.geetest.com/demo/gt/register-test
  188. */
  189. if (api1Resp.status !== 200) {
  190. throw new GSError({
  191. errCode: ERROR_TYPE.API1,
  192. errMsg: `api1 request error, ${await api1Resp.text()}`
  193. })
  194. }
  195. try {
  196. return api1Resp.json()
  197. } catch (e) {
  198. throw new GSError({
  199. errCode: ERROR_TYPE.API1,
  200. errMsg: `api1 request error, response result need json format, but get ${await api1Resp.text()}`
  201. })
  202. }
  203. }
  204. const defaultApi2RespHandler = async api2Resp => {
  205. /**
  206. * api2 官方示例接口
  207. * http://www.geetest.com/demo/gt/validate-test
  208. */
  209. if (api2Resp.status !== 200) {
  210. throw new GSError({
  211. errCode: ERROR_TYPE.API2,
  212. errMsg: `api2 request error, ${await api2Resp.text()}`
  213. })
  214. }
  215. try {
  216. return api2Resp.json()
  217. } catch (e) {
  218. return api2Resp.text()
  219. }
  220. }
  221. /* default captcha funcs end */
  222. export class GSError extends Error {
  223. constructor ({ errCode, errMsg }) {
  224. super(errMsg)
  225. this.name = 'GSError'
  226. this.errCode = errCode
  227. this.errMsg = errMsg
  228. if (typeof Object.setPrototypeOf === 'function') {
  229. Object.setPrototypeOf(this, GSError.prototype)
  230. } else {
  231. this.__proto__ = GSError.prototype
  232. }
  233. stopCaptcha()
  234. }
  235. }