Meteor Altcha
Easy Meteor integration for Altcha. Works with any frontend.
Table of Contents generated with DocToc
Installation
First, add this package via meteor add jkuester:altcha
Then install the Altcha client input type via npm install --save altcha
.
Settings setup
For increased security, the internals are configured via Meteor.settings. If you haven't created a Meteor settings file then you can do it via
echo "{}" > settings.json
So you can start your Meteor app using the settings via meteor --settings=settings.json
.
An example settings for altha may look like he following:
1{ 2 "public": { 3 "altcha": { 4 "challengeUrl": "/altcha-challenge" 5 } 6 }, 7 "altcha": { 8 "algorithm": "SHA-256", 9 "challengeUrl": "/altcha-challenge", 10 "hmacKey": "01234567890abcdefghijklmnopqrstuvwxyz", 11 "maxNumber": 1000000, 12 "expirationAfter": 300000 13 } 14}
The public part is only needed if you want to configure the challenge url via settings.
Server setup
Now you need to initialize it on the server. You can optionally pass a Mongo.Collection as storage for solved challenges (prevent Replay Attacks) or a name of the collection or omit to use an in-memory collection:
1import { Meteor } from 'meteor/meteor'; 2import * as Altcha from 'meteor/jkuester:altcha'; 3 4Meteor.startup(() => { 5 Altcha.init() 6});
As you can see there is an optional debug param, which you can pass a function to, so the internal is passed to it. Beware to disable it in production, though.
Client Setup
On your client you can simply follow the altcha integration guide.
The most minimal setup is to use the altcha component and only configure the challenge-url. The following is a Blaze example, but you are free to use any frontend!
<template name="myForm"> <form id="myForm"> <input type="text" name="username" placeholder="Username" /> <altcha-widget challengeurl="" debug></altcha-widget> <button type="submit">Submit</button> </form> </template>
1import { Template } from 'meteor/templating'; 2import './myForm.html'; 3import 'altcha'; // this is the npm package, not the Meteor package! 4 5Template.registerHelper('settings', () => Meteor.settings.public) 6 7Template.myForm.events({ 8 'submit #myForm' (event) { 9 event.preventDefault() 10 11 const data = Object.fromEntries(new FormData(event.target).entries()) 12 13 // see next section 14 Meteor.call('validateForm', data, (err, res) => { 15 if (err) { 16 alert(err.message) 17 } 18 else { 19 event.target.reset() 20 } 21 }) 22 }, 23});
Service Worker considerations
If you're using a service worker then you should make sure, it ignores the challenge url.
Otherwise, aggressive caching might cause forms to reuse existing challenges which in turn are rejected by default when validating.
Form submission and validation
In the above example we now validate the submitted form by sending the data to a Meteor Method endpoint.
For the above example, the endpoint simply looks like this:
1Meteor.methods({ 2 async validateForm ({ username, altcha }) { 3 const isValid = await Altcha.validate(altcha); 4 if (!isValid) { 5 throw new Meteor.Error(403, 'challenge failed') 6 } 7 // challenge passed, you can 8 // continue with the form submission 9 // data processing 10 } 11})
The default field name for the altcha is altcha
and
you should consider this in your schema, if you do Methods-
validation using a schema, like SimpleSchema, zod, etc.
API Documentation
The API is documented in a separate API.md file.
Contribution
Thank you for considering to contribute! To make both our time worth the effort, please get familiar with the contribution guide, the security guide and the code of conduct.
License
MIT, see license file.