Skip to content

Commit

Permalink
✨ Add ShortlinkApiKey model, so each user can have their own API keys
Browse files Browse the repository at this point in the history
  • Loading branch information
skerit committed Oct 16, 2023
1 parent dc237bc commit 67a85fb
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 17 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.2.2 (WIP)

* Add `ShortlinkApiKey` model, so each user can have their own API keys

## 0.2.1 (2023-10-15)

* Move routes to separate `routes.js` file, so they load in the correct order
Expand Down
4 changes: 0 additions & 4 deletions bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ let options = {
// The base url of the shortlinker
base_url : null,

// The API key to allow remote shortlinks to be made
// @TODO: allow multiple keys
api_key : null,

// QR code settings
qr : {

Expand Down
34 changes: 21 additions & 13 deletions controller/shortlink_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,40 +33,48 @@ Shortlink.setMethod(function setPageTitle(title) {
});

/**
* Create a new shortlink
* Create a new shortlink via the API
*
* @author Jelle De Loecker <[email protected]>
* @since 0.1.0
* @version 0.2.1
* @version 0.2.2
*
* @param {Conduit} conduit
*/
Shortlink.setAction(async function create(conduit) {

this.setPageTitle('Create');
let api_key = conduit.headers.api_key;

if (alchemy.plugins.shortlink.api_key) {
let api_key = conduit.headers.api_key;
if (!api_key || typeof api_key != 'string' || !api_key.trim()) {
return conduit.end({
message : 'No API key was found!'
});
}

if (alchemy.plugins.shortlink.api_key != api_key) {
return conduit.end({
message : 'API key does not match!'
});
}
api_key = api_key.trim();

let KeyModel = this.getModel('ShortlinkApiKey');
let key = await KeyModel.findByValues({
api_key : api_key
});

if (!key) {
return conduit.end({
message : 'API key does not match!'
});
}

let shortlink = this.getModel('Shortlink');

let long_url = conduit.param('long_url') || conduit.param('longurl'),
short_code = conduit.param('shortcode') || conduit.param('short_code'),
document,
user_id = conduit.headers.user_id;
document;

try {
document = await shortlink.createShortUrl({
long_url : long_url,
short_code : short_code,
user_id : user_id
user_id : key.user_id
});
} catch (err) {
console.log('ERR:', err)
Expand Down
90 changes: 90 additions & 0 deletions model/shortlink_api_key_model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* Shortlink API Key model:
* Keys that can be used to create shortlinks per user
*
* @constructor
*
* @author Jelle De Loecker <[email protected]>
* @since 0.2.2
* @version 0.2.2
*/
const ShortlinkApiKey = Function.inherits('Alchemy.Model', 'ShortlinkApiKey');

/**
* Constitute the class wide schema
*
* @author Jelle De Loecker <[email protected]>
* @since 0.2.2
* @version 0.2.2
*/
ShortlinkApiKey.constitute(function addFields() {

// The user this belongs to
this.belongsTo('User');

// The title of this key
this.addField('title', 'String');

// The actual key
this.addField('api_key', 'String', {
description : 'The secret API key',
unique : true,
private : true,
});
});

/**
* Configure the default chimera fieldsets
*
* @author Jelle De Loecker <[email protected]>
* @since 0.2.2
* @version 0.2.2
*/
ShortlinkApiKey.constitute(function chimeraConfig() {

if (!this.chimera) {
return;
}

// Get the list group
let list = this.chimera.getActionFields('list');

list.addField('created');
list.addField('title');
list.addField('user_id');

// Get the edit group
let edit = this.chimera.getActionFields('edit');

edit.addField('user_id');
edit.addField('title');
edit.addField('api_key');
});

/**
* Set the API key before saving
*
* @author Jelle De Loecker <[email protected]>
* @since 0.2.2
* @version 0.2.2
*/
ShortlinkApiKey.setMethod(async function beforeSave(doc) {

let api_key = doc.api_key;

if (api_key) {
api_key = String(api_key).trim().toLowerCase();
doc.api_key = api_key;
}

if (!api_key || typeof api_key != 'string' || api_key.length < 16) {
let existing_record;

do {
api_key = Crypto.randomHex(24);
existing_record = await this.findByValues({api_key});
} while (existing_record);

doc.api_key = api_key;
}
});

0 comments on commit 67a85fb

Please sign in to comment.