Skip to content

Commit

Permalink
Merge pull request #32 from two-factor/zep/pgVerify
Browse files Browse the repository at this point in the history
Zep/pg verify
  • Loading branch information
iangeckeler committed Jul 8, 2019
2 parents 88e9754 + fa40be6 commit c92524c
Show file tree
Hide file tree
Showing 21 changed files with 547 additions and 50 deletions.
Empty file.
Empty file.
3 changes: 3 additions & 0 deletions __tests__/functions/databases/mongoose/verify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
describe('', () => {

}
15 changes: 15 additions & 0 deletions __tests__/functions/databases/postgresql/create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const client = require('../../../../index')(process.env.SID, process.env.AUTH, {
isPostgres: true,
appName: 'testApp',
connectionURI: 'postgres://postgres:yellowjacket@localhost/twoauthtests',
});

// client.create("ian", "+17604207520");

client
.create('ian', '+12016750593')
.then(res => console.log(res))
.catch(err => console.log(err));
// describe("Tests for Postgres Send", () => {

// });
14 changes: 14 additions & 0 deletions __tests__/functions/databases/postgresql/send.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// const client = require("../../../../index")(process.env.SID, process.env.AUTH, {
// isPostgres: true,
// connectionURI: "postgres://student:ilovetesting@localhost/twoauthtests"
// });

// // client.create("ian", "+17604207520");

// client
// .send("ian")
// .then(res => console.log(res))
// .catch(err => console.log(err));
// // describe("Tests for Postgres Send", () => {

// // });
3 changes: 3 additions & 0 deletions __tests__/functions/databases/postgresql/verify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
describe('', () => {

}
17 changes: 8 additions & 9 deletions functions/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,23 @@
// returns a reference to that object
// if rejected, throws error from verify API
function create(userID, phone) {
const client = this.client;
const users = this.users;
const { client, users, appName } = this;

return new Promise((resolve, reject) => {
if (typeof phone !== "string") {
reject(new Error("typeof phone must be string"));
if (typeof phone !== 'string') {
reject(new Error('typeof phone must be string'));
}
if (phone.substring(0, 2) !== "+1") {
reject(new Error("phone must be string formatted as such: +1XXXXXXXXXX"));
if (phone.substring(0, 2) !== '+1') {
reject(new Error('phone must be string formatted as such: +1XXXXXXXXXX'));
}
client.verify.services
.create({ friendlyName: `Service for ${userID}` })
.then(service => {
.create({ friendlyName: `${appName}` })
.then((service) => {
const { sid } = service;
users[userID] = {
userID,
sid,
phone
phone,
};
resolve(users[userID]);
})
Expand Down
22 changes: 10 additions & 12 deletions mongoose/create.js → functions/databases/mongoose/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,28 @@
// returns a reference to that object
// if rejected, throws error from verify API
function create(userID, phone) {
const client = this.client;
const users = this.users;
const TwoAuthUser = this.TwoAuthUser;
const { client, TwoAuthUser, appName } = this;

return new Promise((resolve, reject) => {
if (typeof phone !== "string") {
reject(new Error("typeof phone must be string"));
if (typeof phone !== 'string') {
reject(new Error('typeof phone must be string'));
}
if (phone.substring(0, 2) !== "+1") {
reject(new Error("phone must be string formatted as such: +1XXXXXXXXXX"));
if (phone.substring(0, 2) !== '+1') {
reject(new Error('phone must be string formatted as such: +1XXXXXXXXXX'));
}
client.verify.services
.create({ friendlyName: `Service for ${userID}` })
.then(service => {
.create({ friendlyName: `${appName}` })
.then((service) => {
const { sid } = service;
TwoAuthUser.create({
userID,
sid,
phone
phone,
})
.then(user => {
.then((user) => {
resolve(user);
})
.catch(err => {
.catch((err) => {
reject(err);
});
})
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ function verify(userID, code) {
)
);

return this.client.verify
.services(sid)
return this.client.verify.services(sid)
.verificationChecks.create({
to: phone,
code
Expand Down
18 changes: 18 additions & 0 deletions functions/databases/postgres/configure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
var parse = require("pg-connection-string").parse;
const { Pool } = require("pg");

//function takes in a URI, returns a PG Pool

function generatePool(connectionURI) {
const { user, port, host, database, password } = parse(connectionURI);

return new Pool({
user,
host,
database,
password,
port: port || 5432
});
}

module.exports = generatePool;
35 changes: 35 additions & 0 deletions functions/databases/postgres/create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* eslint-disable func-names */
// eslint-disable-next-line func-names

module.exports = function (userID, phone) {
const { client, appName } = this;
return new Promise((resolve, reject) => {
this.pgConnect()
.then(({ database, done }) => {
if (typeof phone !== 'string') {
reject(new Error('typeof phone must be string'));
}
if (phone.substring(0, 2) !== '+1') {
reject(new Error('phone must be string formatted as such: +1XXXXXXXXXX'));
}
client.verify.services
.create({ friendlyName: `${appName}` })
.then((service) => {
const { sid } = service;
database.query('INSERT INTO twoauthusers(userID, sid, phone) VALUES($1, $2, $3) RETURNING *', [userID, sid, phone])
.then((user) => {
done();
resolve(user);
})
.catch((err) => {
done();
reject(err);
});
})
.catch((err) => {
done();
reject(err);
});
});
});
};
2 changes: 2 additions & 0 deletions functions/databases/postgres/createtable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module.exports =
"CREATE TABLE IF NOT EXISTS twoauthusers (userID VARCHAR(255), sid VARCHAR(255), phone VARCHAR(255))";
42 changes: 42 additions & 0 deletions functions/databases/postgres/send.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
module.exports = function(userID) {
const { pgConnect, client } = this;
return new Promise((resolve, reject) => {
pgConnect()
.then(({ database, done }) => {
const query = "SELECT * FROM twoauthusers WHERE userID=$1";
const values = [String(userID)];
database.query(query, values, (err, res) => {
if (err) reject(err);
const { sid, phone } = res.rows[0];
if (!sid)
reject(new Error("SID Error: No SID exists for this user."));
if (!phone)
reject(
new Error(
"Phone Number Error: No phone number exists for this user."
)
);
//invoke done before your resolve this promise
client.verify
.services(sid)
.verifications.create({
to: phone,
channel: "sms"
})
.then(verification => {
done();
resolve(verification);
})
.catch(err => {
done();
reject(err);
});
});
})
.catch(err => {
done();
reject(err);
//"userID Error: This userID has not been created yet."
});
});
};
50 changes: 50 additions & 0 deletions functions/databases/postgres/verify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
module.exports = function(userID, code) {
const { pgConnect } = this;
return new Promise((resolve, reject) => {
pgConnect()
.then(({ database, done }) => {
//Query to just check if the user was created
const query = "SELECT * FROM twoauthusers WHERE userid=$1";
const values = [String(userID)];

database
.query(query, values)
.then(res => {
const { sid, phone } = res.rows[0];

if (!sid)
reject(new Error("SID Error: No SID exists for this user."));
if (!phone)
reject(
new Error(
"Phone Number Error: No phone number exists for this user."
)
);

return this.client.verify
.services(sid)
.verificationChecks.create({
to: phone,
code
})
.then(verification => {
if (verification.status === "approved") resolve(true);
resolve(false);
})
.catch(err => {
done();
resolve(false)
});
})
.catch(err => {
done();
reject(new Error("Could not find Database at Connection URI."));
});
})
.catch(err => {
done();
reject(new Error("Could not find Database at Connection URI."));
});
});
//invoke done before you reject
};
80 changes: 73 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,58 @@ const create = require("./functions/create.js");
const send = require("./functions/send.js");
const verify = require("./functions/verify.js");

const mongooseCreate = require("./mongoose/create");
const mongooseSend = require("./mongoose/send");
const mongooseVerify = require("./mongoose/verify");
// import mongoose functions
const mongooseCreate = require("./functions/databases/mongoose/create");
const mongooseSend = require("./functions/databases/mongoose/send");
const mongooseVerify = require("./functions/databases/mongoose/verify");
const userSchema = require("./functions/databases/mongoose/userSchema");

const userSchema = require("./mongoose/userSchema");
//import postgres functions
const generatePool = require("./functions/databases/postgres/configure");
const createTable = require("./functions/databases/postgres/createtable");
const postgresCreate = require("./functions/databases/postgres/create");
const postgresSend = require("./functions/databases/postgres/send");
const postgresVerify = require("./functions/databases/postgres/verify");

const connect = (AccSID, AuthToken, mongoURI = null) => {
return new Client(AccSID, AuthToken, mongoURI);
};

// EXAMPLE CONFIG OBJECT
// options = {
// appName: "",
// connectionURI: null,
// isPostgres: null
// }
class Client {
constructor(AccSID, AuthToken, mongoURI = null) {
constructor(
AccSID,
AuthToken,
options = {
appName: "",
connectionURI: null,
isPostgres: false
}
) {
if (typeof options === "string")
throw new Error(
"Options config must be an object, as specified in the documentation."
);
if (!options.hasOwnProperty("isPostgres")) {
options.isPostgres = false;
}
if (!options.hasOwnProperty("appName")) {
options.appName = "";
}
this.appName = options.appName;
this.AccSID = AccSID;
this.AuthToken = AuthToken;
this.client = twilio(this.AccSID, this.AuthToken);
this.users = {};

if (mongoURI !== null) {
if (options.connectionURI !== null && options.isPostgres === false) {
mongoose
.connect(mongoURI)
.connect(options.connectionURI)
.then(db => {
console.log("Two Factor successfully connected to Mongo");
})
Expand All @@ -35,6 +67,40 @@ class Client {
this.create = mongooseCreate;
this.send = mongooseSend;
this.verify = mongooseVerify;
} else if (options.connectionURI !== null && options.isPostgres === true) {
// connect the database and assign a reference to it to our client object
const pgPool = generatePool(options.connectionURI);
let tableCreated = false;
this.pgConnect = function() {
return new Promise((resolve, reject) => {
// connection using created pool
pgPool.connect(function(err, database, done) {
if (err) reject(new Error("Error connecting to Postgres Pool."));
if (!database) {
throw new Error("Could not find Database at Connection URI.");
}
// if table not created yet, create it and modify closure to reflect
if (tableCreated === false) {
database
.query(createTable)
.then(res => {
resolve({ database, done });
tableCreated = true;
})
.catch(e =>
reject(new Error("Error connecting to Postgres Pool."))
);
} else {
resolve({ database, done });
}
});
});
};

// assign the postgres functions to our client object
this.create = postgresCreate;
this.send = postgresSend;
this.verify = postgresVerify;
} else {
this.create = create;
this.send = send;
Expand Down

0 comments on commit c92524c

Please sign in to comment.