112 lines
3.8 KiB
TypeScript
112 lines
3.8 KiB
TypeScript
// (C) Copyright 2015 Moodle Pty Ltd.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import { Component, Input, OnInit } from '@angular/core';
|
|
|
|
import { CoreLang } from '@services/lang';
|
|
import { CoreSites } from '@services/sites';
|
|
import { CoreUtils } from '@services/utils/utils';
|
|
import { CoreText } from '@singletons/text';
|
|
|
|
/**
|
|
* Component that allows answering a recaptcha.
|
|
*/
|
|
@Component({
|
|
selector: 'core-recaptcha',
|
|
templateUrl: 'core-recaptcha.html',
|
|
})
|
|
export class CoreRecaptchaComponent implements OnInit {
|
|
|
|
@Input() model?: Record<string, string>; // The model where to store the recaptcha response.
|
|
@Input() publicKey?: string; // The site public key.
|
|
@Input() modelValueName = 'recaptcharesponse'; // Name of the model property where to store the response.
|
|
@Input() siteUrl?: string; // The site URL. If not defined, current site.
|
|
|
|
expired = false;
|
|
|
|
protected lang?: string;
|
|
|
|
constructor() {
|
|
this.initLang();
|
|
}
|
|
|
|
/**
|
|
* Component being initialized.
|
|
*/
|
|
ngOnInit(): void {
|
|
this.siteUrl = this.siteUrl || CoreSites.getCurrentSite()?.getURL();
|
|
}
|
|
|
|
/**
|
|
* Initialize the lang property.
|
|
*/
|
|
protected async initLang(): Promise<void> {
|
|
this.lang = await CoreLang.getCurrentLanguage();
|
|
}
|
|
|
|
/**
|
|
* Let the user answer the recaptcha.
|
|
*/
|
|
async answerRecaptcha(): Promise<void> {
|
|
// Open the recaptcha challenge in an InAppBrowser.
|
|
// The app used to use an iframe for this, but the app can no longer access the iframe to create the required callbacks.
|
|
// The app cannot render the recaptcha directly because it has problems with the local protocols and domains.
|
|
const src = CoreText.concatenatePaths(this.siteUrl!, 'webservice/recaptcha.php?lang=' + this.lang);
|
|
|
|
const inAppBrowserWindow = CoreUtils.openInApp(src);
|
|
if (!inAppBrowserWindow) {
|
|
return;
|
|
}
|
|
|
|
// Set the callbacks once the page is loaded.
|
|
const loadStopSubscription = inAppBrowserWindow.on('loadstop').subscribe(() => {
|
|
inAppBrowserWindow.executeScript({
|
|
code:
|
|
'window.recaptchacallback = (value) => webkit.messageHandlers.cordova_iab.postMessage(' +
|
|
'JSON.stringify({ action: "callback", value }));' +
|
|
'window.recaptchaexpiredcallback = () => webkit.messageHandlers.cordova_iab.postMessage(' +
|
|
'JSON.stringify({ action: "expired" }));',
|
|
});
|
|
});
|
|
|
|
// Listen for events.
|
|
const messageSubscription = inAppBrowserWindow.on('message').subscribe((event) => {
|
|
if (!event.data) {
|
|
return;
|
|
}
|
|
|
|
if (event.data.action == 'expired') {
|
|
this.expireRecaptchaAnswer();
|
|
} else if (event.data.action == 'callback') {
|
|
this.expired = false;
|
|
this.model![this.modelValueName] = event.data.value;
|
|
|
|
// Close the InAppBrowser now.
|
|
inAppBrowserWindow.close();
|
|
messageSubscription.unsubscribe();
|
|
loadStopSubscription.unsubscribe();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Expire the recaptcha answer.
|
|
*/
|
|
expireRecaptchaAnswer(): void {
|
|
this.expired = true;
|
|
this.model![this.modelValueName] = '';
|
|
}
|
|
|
|
}
|