(rateLimit)
| 837 | } |
| 838 | |
| 839 | static validateRateLimit(rateLimit) { |
| 840 | if (!rateLimit) { |
| 841 | return; |
| 842 | } |
| 843 | if ( |
| 844 | Object.prototype.toString.call(rateLimit) !== '[object Object]' && |
| 845 | !Array.isArray(rateLimit) |
| 846 | ) { |
| 847 | throw `rateLimit must be an array or object`; |
| 848 | } |
| 849 | const options = Array.isArray(rateLimit) ? rateLimit : [rateLimit]; |
| 850 | for (const option of options) { |
| 851 | if (Object.prototype.toString.call(option) !== '[object Object]') { |
| 852 | throw `rateLimit must be an array of objects`; |
| 853 | } |
| 854 | if (option.requestPath == null) { |
| 855 | throw `rateLimit.requestPath must be defined`; |
| 856 | } |
| 857 | if (typeof option.requestPath !== 'string') { |
| 858 | throw `rateLimit.requestPath must be a string`; |
| 859 | } |
| 860 | |
| 861 | // Validate that the path is valid path-to-regexp syntax |
| 862 | try { |
| 863 | pathToRegexp(option.requestPath); |
| 864 | } catch (error) { |
| 865 | throw `rateLimit.requestPath "${option.requestPath}" is not valid: ${error.message}`; |
| 866 | } |
| 867 | |
| 868 | if (option.requestTimeWindow == null) { |
| 869 | throw `rateLimit.requestTimeWindow must be defined`; |
| 870 | } |
| 871 | if (typeof option.requestTimeWindow !== 'number') { |
| 872 | throw `rateLimit.requestTimeWindow must be a number`; |
| 873 | } |
| 874 | if (option.includeInternalRequests && typeof option.includeInternalRequests !== 'boolean') { |
| 875 | throw `rateLimit.includeInternalRequests must be a boolean`; |
| 876 | } |
| 877 | if (option.requestCount == null) { |
| 878 | throw `rateLimit.requestCount must be defined`; |
| 879 | } |
| 880 | if (typeof option.requestCount !== 'number') { |
| 881 | throw `rateLimit.requestCount must be a number`; |
| 882 | } |
| 883 | if (option.errorResponseMessage && typeof option.errorResponseMessage !== 'string') { |
| 884 | throw `rateLimit.errorResponseMessage must be a string`; |
| 885 | } |
| 886 | const options = Object.keys(ParseServer.RateLimitZone); |
| 887 | if (option.zone && !options.includes(option.zone)) { |
| 888 | const formatter = new Intl.ListFormat('en', { style: 'short', type: 'disjunction' }); |
| 889 | throw `rateLimit.zone must be one of ${formatter.format(options)}`; |
| 890 | } |
| 891 | } |
| 892 | } |
| 893 | |
| 894 | generateEmailVerifyTokenExpiresAt() { |
| 895 | if (!this.verifyUserEmails || !this.emailVerifyTokenValidityDuration) { |
no outgoing calls