-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
124 lines (110 loc) · 3.77 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/**
* URL of the verification endpoint.
*/
const VERIFY_ENDPOINT = 'https://www.google.com/recaptcha/api/siteverify'
/**
* The settings that can be passed to configure recaptcha verifiers.
* This includes the secret key, which is mandatory.
*/
export interface RecaptchaVerifierConfig {
secret: string
}
/**
* An object that can be used to verify recaptcha responses (verify method).
* It can be re-configured at a later time by calling init with a new config.
* Additional instances can be obtained by calling the create method.
*/
export interface RecaptchaVerifier {
/**
* Verify a challenge-response.
*
* @param response The user's response to the challenge.
* @param remoteAddress The user's remote address (if available).
* @returns A Promise resolving to whether the response is correct.
*/
(response: any, remoteAddress?: string | null): Promise<boolean>
/**
* Verify a challenge-response.
*
* @param response The user's response to the challenge.
* @param remoteAddress The user's remote address (if available).
* @returns A Promise resolving to whether the response is correct.
*/
verify: (response: any, remoteAddress?: string | null) => Promise<boolean>
/**
* Configure (or re-configure) this instance.
*
* @param config The new configuration.
* @returns This instance, for call chaining.
*/
init: (config: RecaptchaVerifierConfig) => this
/**
* Create an additional verifier instance.
* Note that there is no config inheritance of any kind, so calling this
* method without a config will result in an unconfigured verifier.
*
* @returns The created verifier.
*/
create: (config?: RecaptchaVerifierConfig) => RecaptchaVerifier
}
function getSecret (config: RecaptchaVerifierConfig | { secretKey: string } | { secret_key: string }): string | undefined {
return 'secret' in config
? config.secret
: 'secretKey' in config
? config.secretKey
: config.secret_key
}
/**
* Create a new verifier instance. The returned object exposes a `verify` method
* and an `init` method for (re-)configuration. Moreover, the returned object
* can be called as a function directly, which is synonymous to calling
* `verify`.
*
* @param config The initial config object.
* @returns The created verifier instance.
*/
function createInstance (config?: RecaptchaVerifierConfig): RecaptchaVerifier {
let secret: string | undefined
// this is returned directly, to allow function invocation
const verify = async (response: any, remoteAddress?: string | null): Promise<boolean> => {
if (secret == null) {
throw new Error('secret not configured')
}
const postBody = new URLSearchParams({
secret,
response,
remoteip: remoteAddress ?? ''
}).toString()
const postResponse = await fetch(VERIFY_ENDPOINT, {
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: postBody
})
const data = await postResponse.json()
if (data == null || typeof data !== 'object' || !('success' in data) || typeof data.success !== 'boolean') {
throw new Error('unexpected response')
}
return data.success
}
// this is added as a property to allow newer syntax
verify.verify = verify
// this is added to support (re-)configuration
verify.init = (config: RecaptchaVerifierConfig) => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (typeof config !== 'object' || config == null) {
throw new Error('config object not provided')
}
secret = getSecret(config)
return verify
}
// load initial config if provided
if (config != null) {
verify.init(config)
}
verify.create = createInstance
return verify
}
const main = createInstance()
export default main