Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

coupon-code

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

coupon-code - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

.npmignore

90

coupon-code.js

@@ -7,9 +7,18 @@ // --------------------------------------------------------------------------------------------------------------------

// Web : http://www.chilts.org/blog/
// Email : <chilts@appsattic.com>
// Email : <andychilton@gmail.com>
//
// Copyright (c) : 2011 AppsAttic Ltd
// Copyright (c) : AppsAttic Ltd 2011
// Web : http://www.appsattic.com/
// License : http://opensource.org/licenses/MIT
//
// Copyright (c) : Andrew Chilton 2013
// Web : http://chilts.org/
// License : http://opensource.org/licenses/MIT
//
// --------------------------------------------------------------------------------------------------------------------
// npm
var xtend = require('xtend');
// --------------------------------------------------------------------------------------------------------------------
// constants

@@ -20,8 +29,11 @@

var symbolsObj = {};
var i = 0;
symbolsStr.split('').forEach(function(c) {
symbolsArr.forEach(function(c, i) {
symbolsObj[c] = i;
i++;
});
var defaults = {
parts : 3,
partLen : 4,
};
// --------------------------------------------------------------------------------------------------------------------

@@ -31,7 +43,9 @@ // exports

module.exports.generate = function(opts) {
if ( !opts ) {
opts = {};
}
opts.parts = opts.parts || 3;
opts = xtend({}, defaults, opts);
var parts = [];
var part;
var i;
var j;
// if we have a plaintext, generate a code from that

@@ -44,8 +58,8 @@ if ( opts.plaintext ) {

// default to a random code
var parts = [];
var data;
var part;
for( var i = 0; i < opts.parts; i++ ) {
data = randomSymbol() + randomSymbol() + randomSymbol();
part = data + checkDigitAlg1(data, i+1);
for( i = 0; i < opts.parts; i++ ) {
part = '';
for ( j = 0; j < opts.partLen - 1; j++ ) {
part += randomSymbol();
}
part = part + checkDigitAlg1(part, i+1);
parts.push(part);

@@ -58,29 +72,15 @@ }

module.exports.validate = function(opts) {
if ( !opts ) {
return '';
module.exports.validate = function(code, opts) {
if ( !code ) {
throw new Error("Provide a code to be validated");
}
opts = xtend({}, defaults, opts);
// turn the string into a set of options
if ( typeof opts === 'string' ) {
opts = { code : opts, parts : 3 };
}
// default parts to 3
opts.parts = opts.parts || 3;
// if we have been given no code, this is not valid
if ( !opts.code ) {
return '';
}
var code = opts.code;
// uppercase the code, take out any random chars and replace OIZS with 0125
code = code.toUpperCase();
code = code.replace(/[^0-9A-Z]+/g, '');
code = code.replace(/O/g, '0');
code = code.replace(/I/g, '1');
code = code.replace(/Z/g, '2');
code = code.replace(/S/g, '5');
code = code.toUpperCase()
.replace(/[^0-9A-Z]+/g, '')
.replace(/O/g, '0')
.replace(/I/g, '1')
.replace(/Z/g, '2')
.replace(/S/g, '5');

@@ -91,4 +91,4 @@ // split in the different parts

while( tmp.length > 0 ) {
parts.push( tmp.substr(0, 4) );
tmp = tmp.substr(4);
parts.push( tmp.substr(0, opts.partLen) );
tmp = tmp.substr(opts.partLen);
}

@@ -106,3 +106,3 @@

// check this part has 4 chars
if ( part.length !== 4 ) {
if ( part.length !== opts.partLen ) {
return '';

@@ -112,4 +112,4 @@ }

// split out the data and the check
data = part.substr(0, 3);
check = part.substr(3, 1);
data = part.substr(0, opts.partLen-1);
check = part.substr(opts.partLen-1, 1);

@@ -129,3 +129,3 @@ if ( check !== checkDigitAlg1(data, i+1) ) {

function randomSymbol() {
return symbolsArr[parseInt(Math.random() * symbolsArr.length)];
return symbolsArr[parseInt(Math.random() * symbolsArr.length, 10)];
}

@@ -132,0 +132,0 @@

{
"name": "coupon-code",
"description": "An implementation of Perl's Algorithm::CouponCode for NodeJS.",
"version": "0.1.0",
"version": "0.2.0",
"author": {

@@ -13,5 +13,7 @@ "name":"Andrew Chilton",

"devDependencies": {
"tap": ">= 0.0.14"
"tape": "~2.3.0"
},
"dependencies": {},
"dependencies": {
"xtend": "~2.1.1"
},
"main": "coupon-code.js",

@@ -18,0 +20,0 @@ "engines": {

An implementation of Perl's [Algorithm::CouponCode][couponcode] for NodeJS. Thanks to [Grant][grant] for the
inspiration. :)
# Usage
# Synopsis #
var cc = require('coupon-code');
```
var cc = require('coupon-code');
// generate a 3 part code
cc.generate();
=> '55G2-DHM0-50NN'
// generate a 3 part code
cc.generate();
=> '55G2-DHM0-50NN'
// generate a 4 part code
cc.generate({ parts : 4 });
=> 'U5H9-HKDH-8RNX-1EX7'
// generate a 4 part code
cc.generate({ parts : 4 });
=> 'U5H9-HKDH-8RNX-1EX7'
// same code, just lowercased
cc.validate('55g2-dhm0-50nn');
=> '55G2-DHM0-50NN'
// generate a code with partLen of 6
cc.generate({ partLen : 6 });
=> WYLKQM-U35V40-9N84DA
```
// various letters instead of numbers
cc.validate('SSGZ-DHMO-SONN');
=> '55G2-DHM0-50NN'
Now, when someone types their code in, you can check that it is valid. This means that letters like `O`
are converted to `0` prior to checking.
// wrong last character
cc.validate('55G2-DHM0-50NK');
=> ''
```
// same code, just lowercased
cc.validate('55g2-dhm0-50nn');
=> '55G2-DHM0-50NN'
// not enough chars in the 2nd part
cc.validate('55G2-DHM-50NN');
=> ''
// various letters instead of numbers
cc.validate('SSGZ-DHMO-SONN');
=> '55G2-DHM0-50NN'
# Example
// wrong last character
cc.validate('55G2-DHM0-50NK');
=> ''
// not enough chars in the 2nd part
cc.validate('55G2-DHM-50NN');
=> ''
```
The first thing we do to each code is uppercase it. Then we convert the following letters to numbers:
* O -> 0
* I -> 1
* Z -> 2
* S -> 5
This means [oizs], [OIZS] and [0125] are considered the same code.
# Example #
Let's say you want a user to verify they got something, whether that is an email, letter, fax or carrier pigeon. To

@@ -38,6 +58,8 @@ prove they received it, they have to type the code you sent them into a certain page on your website. You create a code

var cc = require('coupon-code');
```
var cc = require('coupon-code');
var verificationCode = cc.generate();
=> 55G2-DHM0-50NN
var code = cc.generate();
=> 55G2-DHM0-50NN
```

@@ -50,3 +72,5 @@ Time passes, letters get wet, carrier pigeons go on adventures and faxes are just as bad as they ever were. Now the

[s5g2-dhmo-50nn]
```
[s5g2-dhmo-50nn]
```

@@ -64,3 +88,3 @@ Because our codes are case insensitive and have good conversions for similar chars, the code is accepted as correct.

``` bash
$ npm install coupon-code
$ npm install coupon-code
```

@@ -72,10 +96,12 @@

$ npm test
```
$ npm test
```
# Author
Written by [Andrew Chilton](http://www.chilts.org/blog/)
* Written by [Andrew Chilton](http://chilts.org/blog/)
* Copyright 2011 [AppsAttic](http://appsattic.com/)
* Copyright 2013 [Andrew Chilton](http://chilts.org/)
Copyright 2011 [AppsAttic](http://www.appsattic.com/)
# Inspired By

@@ -82,0 +108,0 @@

@@ -15,12 +15,14 @@ // --------------------------------------------------------------------------------------------------------------------

var tap = require("tap"),
test = tap.test,
plan = tap.plan;
// npm
var test = require("tape");
// local
var cc = require('../coupon-code');
// --------------------------------------------------------------------------------------------------------------------
var contents = /^[0-9A-Z-]+$/;
var makeUp = /^\w{4}-\w{4}-\w{4}$/;
var makeUpLong = /^\w{9}-\w{9}-\w{9}-\w{9}-\w{9}$/;
// --------------------------------------------------------------------------------------------------------------------
test("Generating Random Coupon Codes", function (t) {

@@ -30,2 +32,6 @@ // start with two random codes

var code2 = cc.generate();
var codel = cc.generate({
parts : 5,
partLen : 9,
});

@@ -41,4 +47,8 @@ // check their contents and makeUp

t.ok(codel !== '', 'codel should not be empty');
t.ok(codel.match(contents), 'code; comprises uppercase letter, digits and dashes');
t.ok(codel.match(makeUpLong), 'codel pattern is XXXX...-XXXX...-XXXX...etcetc');
// check that they aren't the same
t.notEqual(code1, code2, 'two codes without plaintexts supplied are different');
t.notEqual(code1, code2, 'two codes are different');

@@ -45,0 +55,0 @@ t.end();

@@ -15,5 +15,6 @@ // --------------------------------------------------------------------------------------------------------------------

var tap = require("tap"),
test = tap.test,
plan = tap.plan;
// npm
var test = require("tape");
// local
var cc;

@@ -20,0 +21,0 @@

@@ -15,5 +15,6 @@ // --------------------------------------------------------------------------------------------------------------------

var tap = require("tap"),
test = tap.test,
plan = tap.plan;
// npm
var test = require("tape");
// local
var cc = require('../coupon-code');

@@ -24,47 +25,54 @@

test("Validating Various Inputs", function (t) {
t.ok(!cc.validate(), 'missing code failed validation');
try {
t.ok(!cc.validate(), 'missing code failed validation');
t.fail('Validate should have failed with no code');
}
catch(e) {
t.pass('Validate threw when given no code');
}
t.ok( cc.validate({ code : '1K7Q-CTFM-LMTC' }), 'valid code accepted');
t.ok(!cc.validate({ code : '1K7Q-CTFM' }), 'short code rejected');
t.ok( cc.validate('1K7Q-CTFM-LMTC'), 'valid code accepted');
t.ok(!cc.validate('1K7Q-CTFM'), 'short code rejected');
t.ok( cc.validate({ code : '1K7Q-CTFM', parts : 2 }), "but accepted with correct 'parts'");
t.ok( cc.validate('1K7Q-CTFM', { parts : 2 }), "but accepted with correct 'parts'");
t.ok(!cc.validate('CTFM-1K7Q', { parts : 2 }), "parts must be in correct order");
t.ok(!cc.validate({ code : 'CTFM-1K7Q', parts : 2 }), "parts must be in correct order");
t.ok( cc.validate('QBXA5CV4Q85E-HNYV4U3UD69M-B7XU1BHF3FYE-HXT9LD4Q0DAH-U6WMKC1WNF4N-5PCG5C4JF0GL-5DTUNJ40LRB5', { parts : 7, partLen : 12 }), "but accepted with correct 'parts'");
t.equal( cc.validate({ code : '1k7q-ctfm-lmtc' }), '1K7Q-CTFM-LMTC', "lowercase code is fixed and valid");
t.equal( cc.validate('1k7q-ctfm-lmtc'), '1K7Q-CTFM-LMTC', "lowercase code is fixed and valid");
t.equal(cc.validate({ code : 'I9oD-V467-8D52' }), '190D-V467-8D52', "'o' is fixed to '0'");
t.equal(cc.validate({ code : 'I9oD-V467-8D52' }), '190D-V467-8D52', "'O' is fixed to '0'");
t.equal(cc.validate({ code : 'i9oD-V467-8D52' }), '190D-V467-8D52', "'i' is fixed to '1'");
t.equal(cc.validate({ code : 'i9oD-V467-8D52' }), '190D-V467-8D52', "'I' is fixed to '1'");
t.equal(cc.validate({ code : 'i9oD-V467-8D5z' }), '190D-V467-8D52', "'z' is fixed to '2'");
t.equal(cc.validate({ code : 'i9oD-V467-8D5z' }), '190D-V467-8D52', "'Z' is fixed to '2'");
t.equal(cc.validate({ code : 'i9oD-V467-8Dsz' }), '190D-V467-8D52', "'s' is fixed to '5'");
t.equal(cc.validate({ code : 'i9oD-V467-8Dsz' }), '190D-V467-8D52', "'S' is fixed to '5'");
t.equal(cc.validate('I9oD-V467-8D52'), '190D-V467-8D52', "'o' is fixed to '0'");
t.equal(cc.validate('I9oD-V467-8D52'), '190D-V467-8D52', "'O' is fixed to '0'");
t.equal(cc.validate('i9oD-V467-8D52'), '190D-V467-8D52', "'i' is fixed to '1'");
t.equal(cc.validate('i9oD-V467-8D52'), '190D-V467-8D52', "'I' is fixed to '1'");
t.equal(cc.validate('i9oD-V467-8D5z'), '190D-V467-8D52', "'z' is fixed to '2'");
t.equal(cc.validate('i9oD-V467-8D5z'), '190D-V467-8D52', "'Z' is fixed to '2'");
t.equal(cc.validate('i9oD-V467-8Dsz'), '190D-V467-8D52', "'s' is fixed to '5'");
t.equal(cc.validate('i9oD-V467-8Dsz'), '190D-V467-8D52', "'S' is fixed to '5'");
t.equal(cc.validate({ code : 'i9oD/V467/8Dsz' }), '190D-V467-8D52', "alternative separator is accepted and fixed");
t.equal(cc.validate('i9oD/V467/8Dsz'), '190D-V467-8D52', "alternative separator is accepted and fixed");
t.equal(cc.validate({ code : ' i9oD V467 8Dsz ' }), '190D-V467-8D52', "whitespace is accepted and fixed");
t.equal(cc.validate(' i9oD V467 8Dsz '), '190D-V467-8D52', "whitespace is accepted and fixed");
t.equal(cc.validate({ code : ' i9oD_V467_8Dsz ' }), '190D-V467-8D52', "underscores are accepted and fixed");
t.equal(cc.validate(' i9oD_V467_8Dsz '), '190D-V467-8D52', "underscores are accepted and fixed");
t.equal(cc.validate({ code : 'i9oDV4678Dsz' }), '190D-V467-8D52', "no separator is required");
t.equal(cc.validate('i9oDV4678Dsz'), '190D-V467-8D52', "no separator is required");
t.ok( cc.validate({ code : '1K7Q', parts : 1 }), 'valid code-pretest');
t.ok(!cc.validate({ code : '1K7C', parts : 1 }), 'invalid checkdigit rejected in part 1');
t.ok( cc.validate('1K7Q', { parts : 1 }), 'valid code-pretest');
t.ok(!cc.validate('1K7C', { parts : 1 }), 'invalid checkdigit rejected in part 1');
t.ok( cc.validate({ code : '1K7Q-CTFM', parts : 2 }), 'valid code-pretest');
t.ok(!cc.validate({ code : '1K7Q-CTFW', parts : 2 }), 'invalid checkdigit rejected in part 2');
t.ok( cc.validate('1K7Q-CTFM', { parts : 2 }), 'valid code-pretest');
t.ok(!cc.validate('1K7Q-CTFW', { parts : 2 }), 'invalid checkdigit rejected in part 2');
t.ok( cc.validate({ code : '1K7Q-CTFM-LMTC', parts : 3 }), 'valid code-pretest');
t.ok(!cc.validate({ code : '1K7Q-CTFM-LMT1', parts : 3 }), 'invalid checkdigit rejected in part 3');
t.ok( cc.validate('1K7Q-CTFM-LMTC', { parts : 3 }), 'valid code-pretest');
t.ok(!cc.validate('1K7Q-CTFM-LMT1', { parts : 3 }), 'invalid checkdigit rejected in part 3');
t.ok( cc.validate({ code : '7YQH-1FU7-E1HX-0BG9', parts : 4 }), 'valid code-pretest');
t.ok(!cc.validate({ code : '7YQH-1FU7-E1HX-0BGP', parts : 4 }), 'invalid checkdigit rejected in part 4');
t.ok( cc.validate('7YQH-1FU7-E1HX-0BG9', { parts : 4 }), 'valid code-pretest');
t.ok(!cc.validate('7YQH-1FU7-E1HX-0BGP', { parts : 4 }), 'invalid checkdigit rejected in part 4');
t.ok( cc.validate({ code : 'YENH-UPJK-PTE0-20U6-QYME', parts : 5 }), 'valid code-pretest');
t.ok(!cc.validate({ code : 'YENH-UPJK-PTE0-20U6-QYMT', parts : 5 }), 'invalid checkdigit rejected in part 5');
t.ok( cc.validate('YENH-UPJK-PTE0-20U6-QYME', { parts : 5 }), 'valid code-pretest');
t.ok(!cc.validate('YENH-UPJK-PTE0-20U6-QYMT', { parts : 5 }), 'invalid checkdigit rejected in part 5');
t.ok( cc.validate({ code : 'YENH-UPJK-PTE0-20U6-QYME-RBK1', parts : 6 }), 'valid code-pretest');
t.ok(!cc.validate({ code : 'YENH-UPJK-PTE0-20U6-QYME-RBK2', parts : 6 }), 'invalid checkdigit rejected in part 6');
t.ok( cc.validate('YENH-UPJK-PTE0-20U6-QYME-RBK1', { parts : 6 }), 'valid code-pretest');
t.ok(!cc.validate('YENH-UPJK-PTE0-20U6-QYME-RBK2', { parts : 6 }), 'invalid checkdigit rejected in part 6');

@@ -71,0 +79,0 @@ t.end();

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc