slider-captcha-sdk 1.0.19 → 1.0.20
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.
- package/dist/index.esm.js +95 -101
- package/dist/index.min.js +1 -1
- package/dist/password-validator.d.ts +13 -17
- package/dist/password-validator.esm.js +22 -48
- package/dist/password-validator.min.js +1 -1
- package/dist/slider-captcha.esm.js +73 -53
- package/dist/slider-captcha.min.js +1 -1
- package/package.json +10 -3
package/dist/index.esm.js
CHANGED
|
@@ -13,7 +13,7 @@ class PopupSliderCaptcha {
|
|
|
13
13
|
apiUrl: '/api/captcha',
|
|
14
14
|
verifyUrl: '/api/captcha/verify',
|
|
15
15
|
throttleDelay: 16,
|
|
16
|
-
clickMaskClose: false
|
|
16
|
+
clickMaskClose: false
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
static CSS_CLASSES = {
|
|
@@ -25,7 +25,7 @@ class PopupSliderCaptcha {
|
|
|
25
25
|
btn: 'slider-captcha-btn',
|
|
26
26
|
hint: 'slider-captcha-hint',
|
|
27
27
|
loading: 'slider-captcha-loading',
|
|
28
|
-
error: 'slider-captcha-error'
|
|
28
|
+
error: 'slider-captcha-error'
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
// 优化:提取CSS样式为独立方法,减少主体代码长度
|
|
@@ -39,7 +39,7 @@ class PopupSliderCaptcha {
|
|
|
39
39
|
MAX_RETRY_ATTEMPTS: 3,
|
|
40
40
|
DEFAULT_TIMEOUT: 30000,
|
|
41
41
|
FLOATING_TIME_DURATION: 2500,
|
|
42
|
-
THROTTLE_DELAY: 16
|
|
42
|
+
THROTTLE_DELAY: 16
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
static ERROR_TYPES = {
|
|
@@ -47,7 +47,7 @@ class PopupSliderCaptcha {
|
|
|
47
47
|
TIMEOUT_ERROR: 'TIMEOUT_ERROR',
|
|
48
48
|
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
|
49
49
|
IMAGE_LOAD_ERROR: 'IMAGE_LOAD_ERROR',
|
|
50
|
-
CAPTCHA_DATA_ERROR: 'CAPTCHA_DATA_ERROR'
|
|
50
|
+
CAPTCHA_DATA_ERROR: 'CAPTCHA_DATA_ERROR'
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
constructor(options = {}) {
|
|
@@ -56,7 +56,7 @@ class PopupSliderCaptcha {
|
|
|
56
56
|
...options,
|
|
57
57
|
timeout: options.timeout || PopupSliderCaptcha.CONSTANTS.DEFAULT_TIMEOUT,
|
|
58
58
|
maxRetries: options.maxRetries || PopupSliderCaptcha.CONSTANTS.MAX_RETRY_ATTEMPTS,
|
|
59
|
-
throttleDelay: options.throttleDelay || PopupSliderCaptcha.CONSTANTS.THROTTLE_DELAY
|
|
59
|
+
throttleDelay: options.throttleDelay || PopupSliderCaptcha.CONSTANTS.THROTTLE_DELAY
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
this.elements = {};
|
|
@@ -88,7 +88,7 @@ class PopupSliderCaptcha {
|
|
|
88
88
|
currentX: 0,
|
|
89
89
|
startX: 0,
|
|
90
90
|
retryCount: 0,
|
|
91
|
-
isLoading: false
|
|
91
|
+
isLoading: false
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
@@ -99,7 +99,7 @@ class PopupSliderCaptcha {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
injectStyles() {
|
|
102
|
-
if (document.querySelector('#slider-captcha-styles')) return
|
|
102
|
+
if (document.querySelector('#slider-captcha-styles')) { return }
|
|
103
103
|
|
|
104
104
|
const style = document.createElement('style');
|
|
105
105
|
style.id = 'slider-captcha-styles';
|
|
@@ -128,7 +128,7 @@ class PopupSliderCaptcha {
|
|
|
128
128
|
['btn', 'div', PopupSliderCaptcha.CSS_CLASSES.btn],
|
|
129
129
|
['icon', 'div', '', '→'],
|
|
130
130
|
['hint', 'div', PopupSliderCaptcha.CSS_CLASSES.hint, '向右滑动完成验证'],
|
|
131
|
-
['error', 'div', PopupSliderCaptcha.CSS_CLASSES.error]
|
|
131
|
+
['error', 'div', PopupSliderCaptcha.CSS_CLASSES.error]
|
|
132
132
|
];
|
|
133
133
|
|
|
134
134
|
// 批量创建元素
|
|
@@ -148,8 +148,8 @@ class PopupSliderCaptcha {
|
|
|
148
148
|
|
|
149
149
|
createElement(tag, className = '', textContent = '') {
|
|
150
150
|
const element = document.createElement(tag);
|
|
151
|
-
if (className) element.className = className;
|
|
152
|
-
if (textContent) element.textContent = textContent;
|
|
151
|
+
if (className) { element.className = className; }
|
|
152
|
+
if (textContent) { element.textContent = textContent; }
|
|
153
153
|
return element
|
|
154
154
|
}
|
|
155
155
|
|
|
@@ -166,7 +166,7 @@ class PopupSliderCaptcha {
|
|
|
166
166
|
elements.backgroundImg,
|
|
167
167
|
elements.sliderImg,
|
|
168
168
|
elements.loadingText,
|
|
169
|
-
elements.floatingTime
|
|
169
|
+
elements.floatingTime
|
|
170
170
|
);
|
|
171
171
|
|
|
172
172
|
// 组装滑块轨道
|
|
@@ -194,10 +194,10 @@ class PopupSliderCaptcha {
|
|
|
194
194
|
this.addEventListener(elements.closeBtn, 'click', () => this.hide());
|
|
195
195
|
this.addEventListener(elements.refreshBtn, 'click', () => this.refresh());
|
|
196
196
|
this.addEventListener(elements.overlay, 'click', (e) => {
|
|
197
|
-
if (e.target === elements.overlay && this.options.clickMaskClose) this.hide();
|
|
197
|
+
if (e.target === elements.overlay && this.options.clickMaskClose) { this.hide(); }
|
|
198
198
|
});
|
|
199
199
|
this.addEventListener(document, 'keydown', (e) => {
|
|
200
|
-
if (e.key === 'Escape' && this.state.isVisible) this.hide();
|
|
200
|
+
if (e.key === 'Escape' && this.state.isVisible) { this.hide(); }
|
|
201
201
|
});
|
|
202
202
|
this.addEventListener(document, 'visibilitychange', () => this.handleVisibilityChange());
|
|
203
203
|
|
|
@@ -209,7 +209,7 @@ class PopupSliderCaptcha {
|
|
|
209
209
|
const handlers = {
|
|
210
210
|
start: (e) => this.handleStart(e),
|
|
211
211
|
move: this.throttledHandleMove,
|
|
212
|
-
end: () => this.handleEnd()
|
|
212
|
+
end: () => this.handleEnd()
|
|
213
213
|
};
|
|
214
214
|
|
|
215
215
|
// 滑块事件
|
|
@@ -224,7 +224,7 @@ class PopupSliderCaptcha {
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
addEventListener(element, event, handler, options = {}) {
|
|
227
|
-
if (!element || typeof handler !== 'function') return
|
|
227
|
+
if (!element || typeof handler !== 'function') { return }
|
|
228
228
|
|
|
229
229
|
element.addEventListener(event, handler, options);
|
|
230
230
|
this.eventListeners.push({ element, event, handler, options });
|
|
@@ -248,7 +248,7 @@ class PopupSliderCaptcha {
|
|
|
248
248
|
this.cachedDimensions = {
|
|
249
249
|
trackWidth,
|
|
250
250
|
btnWidth,
|
|
251
|
-
maxX: trackWidth - btnWidth
|
|
251
|
+
maxX: trackWidth - btnWidth
|
|
252
252
|
};
|
|
253
253
|
}
|
|
254
254
|
return this.cachedDimensions
|
|
@@ -261,7 +261,7 @@ class PopupSliderCaptcha {
|
|
|
261
261
|
}
|
|
262
262
|
|
|
263
263
|
handleStart(e) {
|
|
264
|
-
if (!this.captchaData || this.state.isDragging || this.state.isLoading) return
|
|
264
|
+
if (!this.captchaData || this.state.isDragging || this.state.isLoading) { return }
|
|
265
265
|
|
|
266
266
|
e.preventDefault();
|
|
267
267
|
this.state.isDragging = true;
|
|
@@ -275,7 +275,7 @@ class PopupSliderCaptcha {
|
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
handleMove(e) {
|
|
278
|
-
if (!this.state.isDragging) return
|
|
278
|
+
if (!this.state.isDragging) { return }
|
|
279
279
|
e.preventDefault();
|
|
280
280
|
|
|
281
281
|
const clientX = this.getClientX(e);
|
|
@@ -286,12 +286,14 @@ class PopupSliderCaptcha {
|
|
|
286
286
|
this.times.push({ time: Date.now(), position: this.getPosition() });
|
|
287
287
|
|
|
288
288
|
// 优化:使用RAF批量更新
|
|
289
|
-
|
|
289
|
+
if (this.rafId) {
|
|
290
|
+
cancelAnimationFrame(this.rafId);
|
|
291
|
+
}
|
|
290
292
|
this.rafId = requestAnimationFrame(() => this.updateSliderPosition());
|
|
291
293
|
}
|
|
292
294
|
|
|
293
295
|
handleEnd() {
|
|
294
|
-
if (!this.state.isDragging) return
|
|
296
|
+
if (!this.state.isDragging) { return }
|
|
295
297
|
|
|
296
298
|
this.times.push({ time: Date.now(), position: this.getPosition() });
|
|
297
299
|
this.state.isDragging = false;
|
|
@@ -352,7 +354,7 @@ class PopupSliderCaptcha {
|
|
|
352
354
|
elements.hint.style.opacity = '0';
|
|
353
355
|
elements.fingerAnimation.style.display = 'none';
|
|
354
356
|
Object.assign(elements.track.style, { pointerEvents: 'none', opacity: '0.6' });
|
|
355
|
-
}
|
|
357
|
+
}
|
|
356
358
|
};
|
|
357
359
|
|
|
358
360
|
if (updates[state]) {
|
|
@@ -419,7 +421,7 @@ class PopupSliderCaptcha {
|
|
|
419
421
|
[PopupSliderCaptcha.ERROR_TYPES.TIMEOUT_ERROR]: '请求超时,请重试',
|
|
420
422
|
[PopupSliderCaptcha.ERROR_TYPES.VALIDATION_ERROR]: '验证失败,请重试',
|
|
421
423
|
[PopupSliderCaptcha.ERROR_TYPES.IMAGE_LOAD_ERROR]: '图片加载失败,请刷新重试',
|
|
422
|
-
[PopupSliderCaptcha.ERROR_TYPES.CAPTCHA_DATA_ERROR]: '验证码数据错误,请刷新重试'
|
|
424
|
+
[PopupSliderCaptcha.ERROR_TYPES.CAPTCHA_DATA_ERROR]: '验证码数据错误,请刷新重试'
|
|
423
425
|
};
|
|
424
426
|
|
|
425
427
|
const errorMessage = errorMessages[errorType] || message || '未知错误';
|
|
@@ -429,7 +431,7 @@ class PopupSliderCaptcha {
|
|
|
429
431
|
this.options.onError({
|
|
430
432
|
type: errorType,
|
|
431
433
|
message: errorMessage,
|
|
432
|
-
originalError
|
|
434
|
+
originalError
|
|
433
435
|
});
|
|
434
436
|
}
|
|
435
437
|
|
|
@@ -453,13 +455,13 @@ class PopupSliderCaptcha {
|
|
|
453
455
|
method: 'POST',
|
|
454
456
|
headers: {
|
|
455
457
|
'Content-Type': 'application/json',
|
|
456
|
-
...this.options.headers
|
|
458
|
+
...this.options.headers
|
|
457
459
|
},
|
|
458
460
|
body: JSON.stringify({
|
|
459
461
|
timestamp: Date.now(),
|
|
460
|
-
...this.options.requestData
|
|
462
|
+
...this.options.requestData
|
|
461
463
|
}),
|
|
462
|
-
signal: this.abortController.signal
|
|
464
|
+
signal: this.abortController.signal
|
|
463
465
|
});
|
|
464
466
|
|
|
465
467
|
if (!response.ok) {
|
|
@@ -492,7 +494,7 @@ class PopupSliderCaptcha {
|
|
|
492
494
|
|
|
493
495
|
// 优化:添加验证码数据验证方法
|
|
494
496
|
validateCaptchaData(data) {
|
|
495
|
-
if (!data || typeof data !== 'object') return false
|
|
497
|
+
if (!data || typeof data !== 'object') { return false }
|
|
496
498
|
|
|
497
499
|
const requiredFields = [
|
|
498
500
|
'canvasSrc',
|
|
@@ -502,7 +504,7 @@ class PopupSliderCaptcha {
|
|
|
502
504
|
'blockWidth',
|
|
503
505
|
'blockHeight',
|
|
504
506
|
'blockY',
|
|
505
|
-
'nonceStr'
|
|
507
|
+
'nonceStr'
|
|
506
508
|
];
|
|
507
509
|
const dataObj = data.data || data;
|
|
508
510
|
|
|
@@ -516,17 +518,33 @@ class PopupSliderCaptcha {
|
|
|
516
518
|
return new Promise((resolve, reject) => {
|
|
517
519
|
let hasError = false;
|
|
518
520
|
|
|
521
|
+
// const _onLoad = () => {
|
|
522
|
+
// if (hasError) { return }
|
|
523
|
+
// loadedCount++
|
|
524
|
+
// if (loadedCount === 2) {
|
|
525
|
+
// this.hideLoading()
|
|
526
|
+
// resolve()
|
|
527
|
+
// }
|
|
528
|
+
// }
|
|
529
|
+
//
|
|
530
|
+
// const _onError = (error) => {
|
|
531
|
+
// if (hasError) { return }
|
|
532
|
+
// hasError = true
|
|
533
|
+
// this.handleError(PopupSliderCaptcha.ERROR_TYPES.IMAGE_LOAD_ERROR, '图片加载失败', error)
|
|
534
|
+
// reject(new Error('图片加载失败'))
|
|
535
|
+
// }
|
|
536
|
+
|
|
519
537
|
// 优化:并行加载图片,提高性能
|
|
520
538
|
const loadPromises = [
|
|
521
539
|
this.loadImageAsync(this.elements.backgroundImg, this.captchaData.canvasSrc, {
|
|
522
540
|
width: this.captchaData.canvasWidth,
|
|
523
|
-
height: this.captchaData.canvasHeight
|
|
541
|
+
height: this.captchaData.canvasHeight
|
|
524
542
|
}),
|
|
525
543
|
this.loadImageAsync(this.elements.sliderImg, this.captchaData.blockSrc, {
|
|
526
544
|
width: this.captchaData.blockWidth,
|
|
527
545
|
height: this.captchaData.blockHeight,
|
|
528
|
-
top: this.captchaData.blockY
|
|
529
|
-
})
|
|
546
|
+
top: this.captchaData.blockY
|
|
547
|
+
})
|
|
530
548
|
];
|
|
531
549
|
|
|
532
550
|
Promise.all(loadPromises)
|
|
@@ -562,16 +580,16 @@ class PopupSliderCaptcha {
|
|
|
562
580
|
reject(new Error('图片加载超时'));
|
|
563
581
|
}, 10000); // 10秒超时
|
|
564
582
|
|
|
565
|
-
imgElement.onload = ()
|
|
583
|
+
imgElement.onload = function onImageLoad() {
|
|
566
584
|
this.safeClearTimeout(timeoutId);
|
|
567
585
|
this.imageCache.set(src, imgElement.cloneNode());
|
|
568
586
|
resolve();
|
|
569
|
-
};
|
|
587
|
+
}.bind(this);
|
|
570
588
|
|
|
571
|
-
imgElement.onerror = (error)
|
|
589
|
+
imgElement.onerror = function onImageError(error) {
|
|
572
590
|
this.safeClearTimeout(timeoutId);
|
|
573
591
|
reject(error);
|
|
574
|
-
};
|
|
592
|
+
}.bind(this);
|
|
575
593
|
|
|
576
594
|
imgElement.src = src;
|
|
577
595
|
this.applyStyles(imgElement, styles);
|
|
@@ -581,7 +599,7 @@ class PopupSliderCaptcha {
|
|
|
581
599
|
// 优化:提取样式应用逻辑
|
|
582
600
|
applyStyles(element, styles) {
|
|
583
601
|
Object.entries(styles).forEach(([key, value]) => {
|
|
584
|
-
element.style[key] = typeof value === 'number' ? value
|
|
602
|
+
element.style[key] = typeof value === 'number' ? `${value}px` : value;
|
|
585
603
|
});
|
|
586
604
|
}
|
|
587
605
|
|
|
@@ -591,7 +609,7 @@ class PopupSliderCaptcha {
|
|
|
591
609
|
this.batchUpdateStyles({
|
|
592
610
|
container: { display: 'block' },
|
|
593
611
|
loadingText: { display: 'flex' },
|
|
594
|
-
error: { display: 'none' }
|
|
612
|
+
error: { display: 'none' }
|
|
595
613
|
});
|
|
596
614
|
this.updateUIState('loading');
|
|
597
615
|
}
|
|
@@ -606,14 +624,14 @@ class PopupSliderCaptcha {
|
|
|
606
624
|
this.batchUpdateStyles({
|
|
607
625
|
container: { display: 'block' },
|
|
608
626
|
track: { display: 'block' },
|
|
609
|
-
error: { display: 'none' }
|
|
627
|
+
error: { display: 'none' }
|
|
610
628
|
});
|
|
611
629
|
}
|
|
612
630
|
|
|
613
631
|
showError(message) {
|
|
614
632
|
this.hideLoading();
|
|
615
633
|
this.batchUpdateStyles({
|
|
616
|
-
error: { display: 'block', textContent: message }
|
|
634
|
+
error: { display: 'block', textContent: message }
|
|
617
635
|
});
|
|
618
636
|
}
|
|
619
637
|
|
|
@@ -652,17 +670,17 @@ class PopupSliderCaptcha {
|
|
|
652
670
|
method: 'POST',
|
|
653
671
|
headers: {
|
|
654
672
|
'Content-Type': 'application/json',
|
|
655
|
-
...this.options.headers
|
|
673
|
+
...this.options.headers
|
|
656
674
|
},
|
|
657
675
|
body: JSON.stringify({
|
|
658
676
|
loginVo: {
|
|
659
677
|
nonceStr: this.captchaData.nonceStr,
|
|
660
|
-
value: this.getPosition()
|
|
678
|
+
value: this.getPosition()
|
|
661
679
|
},
|
|
662
680
|
dragEventList: [...this.times],
|
|
663
|
-
...this.options.verifyData
|
|
681
|
+
...this.options.verifyData
|
|
664
682
|
}),
|
|
665
|
-
signal: this.abortController.signal
|
|
683
|
+
signal: this.abortController.signal
|
|
666
684
|
});
|
|
667
685
|
|
|
668
686
|
if (!response.ok) {
|
|
@@ -693,7 +711,7 @@ class PopupSliderCaptcha {
|
|
|
693
711
|
|
|
694
712
|
// 优化:添加验证成功判断方法
|
|
695
713
|
isVerifySuccess(data) {
|
|
696
|
-
if (!data || typeof data !== 'object') return false
|
|
714
|
+
if (!data || typeof data !== 'object') { return false }
|
|
697
715
|
|
|
698
716
|
// 支持多种成功标识
|
|
699
717
|
const successIndicators = [
|
|
@@ -701,16 +719,16 @@ class PopupSliderCaptcha {
|
|
|
701
719
|
data.code === 0,
|
|
702
720
|
data.success === true,
|
|
703
721
|
data.status === 'success',
|
|
704
|
-
data.result === true
|
|
722
|
+
data.result === true
|
|
705
723
|
];
|
|
706
724
|
|
|
707
725
|
return successIndicators.some((indicator) => indicator === true)
|
|
708
726
|
}
|
|
709
727
|
|
|
710
728
|
onVerifySuccess(ticket) {
|
|
711
|
-
const duration = this.dragStartTime
|
|
712
|
-
|
|
713
|
-
|
|
729
|
+
const duration = this.dragStartTime ?
|
|
730
|
+
Date.now() - this.dragStartTime :
|
|
731
|
+
Date.now() - this.startTime;
|
|
714
732
|
const durationText = `验证成功!耗时:${(duration / 1000).toFixed(2)}s`;
|
|
715
733
|
|
|
716
734
|
this.updateUIState('success');
|
|
@@ -718,9 +736,9 @@ class PopupSliderCaptcha {
|
|
|
718
736
|
|
|
719
737
|
this.safeSetTimeout(() => {
|
|
720
738
|
this.options.onSuccess?.({
|
|
721
|
-
ticket
|
|
739
|
+
ticket,
|
|
722
740
|
timestamp: Date.now(),
|
|
723
|
-
duration
|
|
741
|
+
duration
|
|
724
742
|
});
|
|
725
743
|
this.hide();
|
|
726
744
|
}, 2000);
|
|
@@ -759,7 +777,7 @@ class PopupSliderCaptcha {
|
|
|
759
777
|
isDragging: false,
|
|
760
778
|
currentX: 0,
|
|
761
779
|
startX: 0,
|
|
762
|
-
isLoading: false
|
|
780
|
+
isLoading: false
|
|
763
781
|
});
|
|
764
782
|
|
|
765
783
|
this.times = [];
|
|
@@ -831,13 +849,15 @@ class PopupSliderCaptcha {
|
|
|
831
849
|
// 工具函数:节流
|
|
832
850
|
throttle(func, delay) {
|
|
833
851
|
let lastCall = 0;
|
|
834
|
-
|
|
852
|
+
const throttledFunction = (...args) => {
|
|
835
853
|
const now = Date.now();
|
|
836
854
|
if (now - lastCall >= delay) {
|
|
837
855
|
lastCall = now;
|
|
838
856
|
return func.apply(this, args)
|
|
839
857
|
}
|
|
840
|
-
|
|
858
|
+
return undefined
|
|
859
|
+
};
|
|
860
|
+
return throttledFunction
|
|
841
861
|
}
|
|
842
862
|
|
|
843
863
|
destroy() {
|
|
@@ -924,11 +944,10 @@ var PopupSliderCaptcha$1 = PopupSliderCaptcha;
|
|
|
924
944
|
* 提供密码加密和校验功能
|
|
925
945
|
*/
|
|
926
946
|
class PasswordValidator {
|
|
927
|
-
// 优化:添加常量定义
|
|
928
947
|
static CONSTANTS = {
|
|
929
948
|
DEFAULT_TIMEOUT: 10000,
|
|
930
949
|
CACHE_DURATION: 5 * 60 * 1000, // 5分钟缓存
|
|
931
|
-
MIN_PASSWORD_LENGTH: 1
|
|
950
|
+
MIN_PASSWORD_LENGTH: 1
|
|
932
951
|
}
|
|
933
952
|
|
|
934
953
|
static ERROR_TYPES = {
|
|
@@ -936,7 +955,7 @@ class PasswordValidator {
|
|
|
936
955
|
TIMEOUT_ERROR: 'TIMEOUT_ERROR',
|
|
937
956
|
ENCRYPTION_ERROR: 'ENCRYPTION_ERROR',
|
|
938
957
|
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
|
939
|
-
PUBLIC_KEY_ERROR: 'PUBLIC_KEY_ERROR'
|
|
958
|
+
PUBLIC_KEY_ERROR: 'PUBLIC_KEY_ERROR'
|
|
940
959
|
}
|
|
941
960
|
|
|
942
961
|
constructor(options = {}) {
|
|
@@ -946,7 +965,7 @@ class PasswordValidator {
|
|
|
946
965
|
timeout: options.timeout || PasswordValidator.CONSTANTS.DEFAULT_TIMEOUT,
|
|
947
966
|
headers: options.headers || {},
|
|
948
967
|
cacheDuration: options.cacheDuration || PasswordValidator.CONSTANTS.CACHE_DURATION,
|
|
949
|
-
...options
|
|
968
|
+
...options
|
|
950
969
|
};
|
|
951
970
|
|
|
952
971
|
// 缓存公钥,避免重复请求
|
|
@@ -966,11 +985,11 @@ class PasswordValidator {
|
|
|
966
985
|
|
|
967
986
|
try {
|
|
968
987
|
const response = await this.makeRequest(this.options.publicKeyUrl, {
|
|
969
|
-
method: 'GET'
|
|
988
|
+
method: 'GET'
|
|
970
989
|
});
|
|
971
990
|
|
|
972
991
|
if (!this.isSuccessResponse(response)) {
|
|
973
|
-
throw new Error(
|
|
992
|
+
throw new Error(`获取公钥失败:${response.message || response.msg || '未知错误'}`)
|
|
974
993
|
}
|
|
975
994
|
|
|
976
995
|
// 验证公钥格式
|
|
@@ -987,7 +1006,7 @@ class PasswordValidator {
|
|
|
987
1006
|
} catch (error) {
|
|
988
1007
|
console.error('获取公钥失败:', error);
|
|
989
1008
|
this.handleError(PasswordValidator.ERROR_TYPES.PUBLIC_KEY_ERROR, error.message, error);
|
|
990
|
-
throw new Error(
|
|
1009
|
+
throw new Error(`获取公钥失败: ${error.message}`)
|
|
991
1010
|
}
|
|
992
1011
|
}
|
|
993
1012
|
|
|
@@ -1002,7 +1021,7 @@ class PasswordValidator {
|
|
|
1002
1021
|
response.code === 0,
|
|
1003
1022
|
response.success === true,
|
|
1004
1023
|
response.status === 'success',
|
|
1005
|
-
response.result === true
|
|
1024
|
+
response.result === true
|
|
1006
1025
|
];
|
|
1007
1026
|
|
|
1008
1027
|
return successIndicators.some((indicator) => indicator === true)
|
|
@@ -1014,7 +1033,7 @@ class PasswordValidator {
|
|
|
1014
1033
|
[PasswordValidator.ERROR_TYPES.TIMEOUT_ERROR]: '请求超时,请重试',
|
|
1015
1034
|
[PasswordValidator.ERROR_TYPES.ENCRYPTION_ERROR]: '密码加密失败',
|
|
1016
1035
|
[PasswordValidator.ERROR_TYPES.VALIDATION_ERROR]: '密码验证失败',
|
|
1017
|
-
[PasswordValidator.ERROR_TYPES.PUBLIC_KEY_ERROR]: '获取公钥失败'
|
|
1036
|
+
[PasswordValidator.ERROR_TYPES.PUBLIC_KEY_ERROR]: '获取公钥失败'
|
|
1018
1037
|
};
|
|
1019
1038
|
|
|
1020
1039
|
const errorMessage = errorMessages[errorType] || message || '未知错误';
|
|
@@ -1024,7 +1043,7 @@ class PasswordValidator {
|
|
|
1024
1043
|
this.options.onError({
|
|
1025
1044
|
type: errorType,
|
|
1026
1045
|
message: errorMessage,
|
|
1027
|
-
originalError
|
|
1046
|
+
originalError
|
|
1028
1047
|
});
|
|
1029
1048
|
}
|
|
1030
1049
|
|
|
@@ -1067,7 +1086,7 @@ class PasswordValidator {
|
|
|
1067
1086
|
} catch (error) {
|
|
1068
1087
|
console.error('密码加密失败:', error);
|
|
1069
1088
|
this.handleError(PasswordValidator.ERROR_TYPES.ENCRYPTION_ERROR, error.message, error);
|
|
1070
|
-
throw new Error(
|
|
1089
|
+
throw new Error(`密码加密失败: ${error.message}`)
|
|
1071
1090
|
}
|
|
1072
1091
|
}
|
|
1073
1092
|
|
|
@@ -1094,11 +1113,11 @@ class PasswordValidator {
|
|
|
1094
1113
|
const response = await this.makeRequest(this.options.validateUrl, {
|
|
1095
1114
|
method: 'POST',
|
|
1096
1115
|
body: JSON.stringify({
|
|
1097
|
-
userName
|
|
1116
|
+
userName,
|
|
1098
1117
|
password: encryptedPassword,
|
|
1099
1118
|
timestamp: Date.now(),
|
|
1100
|
-
...additionalData
|
|
1101
|
-
})
|
|
1119
|
+
...additionalData
|
|
1120
|
+
})
|
|
1102
1121
|
});
|
|
1103
1122
|
|
|
1104
1123
|
return {
|
|
@@ -1106,7 +1125,7 @@ class PasswordValidator {
|
|
|
1106
1125
|
data: response.data || response.result,
|
|
1107
1126
|
message: response.message || response.msg || '验证完成',
|
|
1108
1127
|
code: response.code || response.status,
|
|
1109
|
-
originalResponse: response
|
|
1128
|
+
originalResponse: response
|
|
1110
1129
|
}
|
|
1111
1130
|
} catch (error) {
|
|
1112
1131
|
console.error('密码校验失败:', error);
|
|
@@ -1127,7 +1146,7 @@ class PasswordValidator {
|
|
|
1127
1146
|
success: false,
|
|
1128
1147
|
message: error.message || '密码校验失败',
|
|
1129
1148
|
code: errorType,
|
|
1130
|
-
error
|
|
1149
|
+
error
|
|
1131
1150
|
}
|
|
1132
1151
|
}
|
|
1133
1152
|
}
|
|
@@ -1152,9 +1171,9 @@ class PasswordValidator {
|
|
|
1152
1171
|
headers: {
|
|
1153
1172
|
'Content-Type': 'application/json',
|
|
1154
1173
|
...this.options.headers,
|
|
1155
|
-
...options.headers
|
|
1174
|
+
...options.headers
|
|
1156
1175
|
},
|
|
1157
|
-
signal: abortController.signal
|
|
1176
|
+
signal: abortController.signal
|
|
1158
1177
|
});
|
|
1159
1178
|
|
|
1160
1179
|
clearTimeout(timeoutId);
|
|
@@ -1206,37 +1225,16 @@ class PasswordValidator {
|
|
|
1206
1225
|
this.clearCache();
|
|
1207
1226
|
}
|
|
1208
1227
|
|
|
1209
|
-
/**
|
|
1210
|
-
* 取消当前请求
|
|
1211
|
-
* 注意:由于现在每个请求使用独立的AbortController,此方法主要用于向后兼容
|
|
1212
|
-
*/
|
|
1213
|
-
cancelRequest() {
|
|
1214
|
-
// 由于现在每个请求使用独立的AbortController,无法直接取消所有请求
|
|
1215
|
-
// 如果需要取消特定请求,建议在调用validatePassword时保存返回的Promise并手动处理
|
|
1216
|
-
console.warn('cancelRequest方法已过时,现在每个请求使用独立的AbortController');
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
/**
|
|
1220
|
-
* 检查是否正在请求中
|
|
1221
|
-
* @returns {boolean} 是否正在请求
|
|
1222
|
-
* 注意:由于现在每个请求使用独立的AbortController,此方法无法准确判断
|
|
1223
|
-
*/
|
|
1224
|
-
isRequesting() {
|
|
1225
|
-
// 由于现在每个请求使用独立的AbortController,无法准确判断是否正在请求
|
|
1226
|
-
console.warn('isRequesting方法已过时,现在每个请求使用独立的AbortController');
|
|
1227
|
-
return false
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
1228
|
/**
|
|
1231
1229
|
* 获取缓存状态
|
|
1232
1230
|
* @returns {Object} 缓存状态信息
|
|
1233
1231
|
*/
|
|
1234
1232
|
getCacheStatus() {
|
|
1235
1233
|
return {
|
|
1236
|
-
hasCache:
|
|
1234
|
+
hasCache: Boolean(this.publicKeyCache),
|
|
1237
1235
|
isExpired: this.publicKeyExpiry ? Date.now() > this.publicKeyExpiry : true,
|
|
1238
1236
|
expiryTime: this.publicKeyExpiry,
|
|
1239
|
-
remainingTime: this.publicKeyExpiry ? Math.max(0, this.publicKeyExpiry - Date.now()) : 0
|
|
1237
|
+
remainingTime: this.publicKeyExpiry ? Math.max(0, this.publicKeyExpiry - Date.now()) : 0
|
|
1240
1238
|
}
|
|
1241
1239
|
}
|
|
1242
1240
|
|
|
@@ -1245,9 +1243,6 @@ class PasswordValidator {
|
|
|
1245
1243
|
*/
|
|
1246
1244
|
destroy() {
|
|
1247
1245
|
try {
|
|
1248
|
-
// 取消所有进行中的请求
|
|
1249
|
-
this.cancelRequest();
|
|
1250
|
-
|
|
1251
1246
|
// 清除缓存
|
|
1252
1247
|
this.clearCache();
|
|
1253
1248
|
|
|
@@ -1276,15 +1271,14 @@ function createPasswordValidator(options) {
|
|
|
1276
1271
|
/**
|
|
1277
1272
|
* 快速校验密码的便捷函数
|
|
1278
1273
|
* @param {string} password 密码
|
|
1274
|
+
* @param {string} userName 用户名
|
|
1279
1275
|
* @param {Object} options 配置选项
|
|
1280
1276
|
* @param {Object} additionalData 额外数据
|
|
1281
1277
|
* @returns {Promise<Object>} 校验结果
|
|
1282
1278
|
*/
|
|
1283
|
-
|
|
1279
|
+
function validatePassword(password, userName, options = {}, additionalData = {}) {
|
|
1284
1280
|
const validator = new PasswordValidator(options);
|
|
1285
|
-
|
|
1286
|
-
const userName = additionalData.userName || '';
|
|
1287
|
-
return await validator.validatePassword(password, userName, additionalData)
|
|
1281
|
+
return validator.validatePassword(password, userName, additionalData)
|
|
1288
1282
|
}
|
|
1289
1283
|
|
|
1290
1284
|
// 导入滑块验证码组件(使用默认导入)
|