Skip to content

Commit

Permalink
Request-a-copy improv: Altcha recaptcha component and service
Browse files Browse the repository at this point in the history
  • Loading branch information
kshepherd committed Feb 13, 2025
1 parent 9c24e6c commit 0922d92
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 0 deletions.
25 changes: 25 additions & 0 deletions src/app/core/data/proof-of-work-captcha-data.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { HALEndpointService } from '../shared/hal-endpoint.service';

@Injectable({ providedIn: 'root' })
export class ProofOfWorkCaptchaDataService {

private linkPath = 'captcha';

constructor(
private halService: HALEndpointService) {
}

public getChallengeHref(): Observable<string> {
return this.getEndpoint().pipe(
map((endpoint) => endpoint + '/challenge'),
);
}

protected getEndpoint(): Observable<string> {
return this.halService.getEndpoint(this.linkPath);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<altcha-widget
id="altcha-widget"
auto="{{ autoload }}"
expire="100000"
workers=16
challengeurl="{{ challengeUrl }}"></altcha-widget>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {
ComponentFixture,
TestBed,
} from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';

import { AltchaCaptchaComponent } from './altcha-captcha.component';

describe('AltchaCaptchaComponent', () => {
let component: AltchaCaptchaComponent;
let fixture: ComponentFixture<AltchaCaptchaComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
AltchaCaptchaComponent,
],
}).compileComponents();

fixture = TestBed.createComponent(AltchaCaptchaComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create component successfully', () => {
expect(component).toBeTruthy();
});

it('should emit payload when verification is successful', () => {
const testPayload = 'test-payload';
const payloadSpy = jasmine.createSpy('payloadSpy');
component.payload.subscribe(payloadSpy);

const event = new CustomEvent('statechange', {
detail: {
state: 'verified',
payload: testPayload,
},
});

document.querySelector('#altcha-widget').dispatchEvent(event);

expect(payloadSpy).toHaveBeenCalledWith(testPayload);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
AsyncPipe,
NgIf,
} from '@angular/common';
import {
Component,
CUSTOM_ELEMENTS_SCHEMA,
EventEmitter,
Input,
OnInit,
Output,
} from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { RouterLink } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';

import { VarDirective } from '../../../shared/utils/var.directive';

@Component({
selector: 'ds-altcha-captcha',
templateUrl: './altcha-captcha.component.html',
imports: [
TranslateModule,
RouterLink,
AsyncPipe,
ReactiveFormsModule,
NgIf,
VarDirective,
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
standalone: true,
})
export class AltchaCaptchaComponent implements OnInit {

@Input() challengeUrl: string;
@Input() autoload: string;
@Input() debug: boolean;
@Output() payload = new EventEmitter<string>;

ngOnInit(): void {
document.querySelector('#altcha-widget').addEventListener('statechange', (ev: any) => {
// state can be: unverified, verifying, verified, error
if (ev.detail.state === 'verified') {
// payload contains base64 encoded data for the server
this.payload.emit(ev.detail.payload);
}
});
}

}

0 comments on commit 0922d92

Please sign in to comment.