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] = '';
}
}