Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

compressing the logic I hope

  • Loading branch information...
commit 9c2fc705f286e40f7f1e9ed4d728ebe9915dd407 1 parent 7aa9928
Chris Anderson jchris authored

Showing 2 changed files with 209 additions and 0 deletions. Show diff stats Hide diff stats

  1. +56 0 logic/channels.js
  2. +153 0 logic/pairDevice.js
56 logic/channels.js
... ... @@ -0,0 +1,56 @@
  1 +
  2 +exports.bind = function(control){
  3 + control.safe("channel", "new", newChannel);
  4 + return control;
  5 +};
  6 +
  7 +function findServerUrl(config) {
  8 + var cloudControl = config['cloud-control']
  9 + , cloudDesign = config['cloud-design']
  10 + , d = cloudControl.split('/');
  11 + d.pop();
  12 + return d.join('/');
  13 +};
  14 +
  15 +
  16 +function newChannel(doc) {
  17 + var db_name = "db-"+doc._id;
  18 + if (doc["public"]) {
  19 + console.log("PDI","please implement public databases")
  20 + } else {
  21 + coux.put([serverUrl, db_name], function(err, resp) {
  22 + if (err) {
  23 + // 412 means the db already exists
  24 + doc.state = "error";
  25 + doc.error = err;
  26 + coux.put([cloudControl, doc._id], doc, function(err, ok) {
  27 + if (err) console.error(err);
  28 + })
  29 + console.log(err, resp);
  30 + } else {
  31 + // only set up creds the first time
  32 + coux([serverUrl, db_name, "_security"],function(err, sec) {
  33 + if (err) {sec = {members:{names:[],roles:[]}}}
  34 + if (sec.members.names.indexOf(doc.owner) == -1) {
  35 + sec.members.names.push(doc.owner);
  36 + coux.put([serverUrl, db_name, "_security"], sec, e(function(err, sec) {
  37 + // replicate the design docs to the new db
  38 + coux.post([serverUrl, "_replicate"], {
  39 + source : cloudDesign,
  40 + target : db_name
  41 + }, e(function(err, ok) {
  42 + doc.state = "ready";
  43 + doc.syncpoint = serverUrl + '/' + db_name;
  44 + coux.put([cloudControl, doc._id], doc, function(err, ok) {
  45 + if (err) console.error(err);
  46 + })
  47 + }))
  48 + }));
  49 + }
  50 +
  51 + });
  52 +
  53 + }
  54 + });
  55 + }
  56 +}
153 logic/pairDevice.js
... ... @@ -0,0 +1,153 @@
  1 +// binds to the control database, runs document logic
  2 +
  3 +exports.bind = function(control) {
  4 + control.safe("confirm","clicked", confirmClicked);
  5 + control.safe("device", "confirmed", deviceConfirmed);
  6 + // sends an email, not safe to run twice
  7 + control.unsafe("device", "new", deviceNew);
  8 +};
  9 +
  10 +function confirmClicked(doc) {
  11 + var confirm_code = doc.confirm_code;
  12 + var device_code = doc.device_code;
  13 + // load the device doc with confirm_code == code
  14 + // TODO use a real view
  15 + coux([cloudControl, "_all_docs", {include_docs : true}], e(function(err, view) {
  16 + var deviceDoc;
  17 + view.rows.forEach(function(row) {
  18 + if (row.doc.confirm_code && row.doc.confirm_code == confirm_code &&
  19 + row.doc.device_code && row.doc.device_code == device_code &&
  20 + row.doc.type && row.doc.type == "device") {
  21 + deviceDoc = row.doc;
  22 + }
  23 + });
  24 + if (deviceDoc) {
  25 + deviceDoc.state = "confirmed";
  26 + coux.put([cloudControl, deviceDoc._id], deviceDoc, e(function(err, ok) {
  27 + doc.state = "used";
  28 + coux.put([cloudControl, doc._id], doc, e());
  29 + }));
  30 + } else {
  31 + doc.state = "error";
  32 + doc.error = "no matching device";
  33 + coux.put([cloudControl, doc._id], doc, e());
  34 + }
  35 + }));
  36 +}
  37 +
  38 +
  39 +function deviceConfirmed(deviceDoc) {
  40 + // ensure the user exists and make sure the device has a delegate on it
  41 + // move device_creds to user document, so the device can use them to auth as the user
  42 + ensureUserDoc(serverUrl, deviceDoc.owner, function(err, userDoc) {
  43 + console.log("ensuredUserDoc")
  44 + userDoc = applyOAuth(userDoc, deviceDoc, serverUrl, o(function(err, userDoc) {
  45 + if (err && err.error != 'modification_not_allowed') { // iris couch oauth workaround
  46 + deviceDoc.state = "error";
  47 + deviceDoc.error = err;
  48 + coux.put([cloudControl, deviceDoc._id], deviceDoc, e());
  49 + } else {
  50 + if (userDoc) {
  51 + coux.put([serverUrl, "_users", userDoc._id], userDoc, e(function(err) {
  52 + deviceDoc.state = "active";
  53 + coux.put([cloudControl, deviceDoc._id], deviceDoc, e());
  54 + }))
  55 + } else {
  56 + console.log("activateDeviceDoc")
  57 + deviceDoc.state = "active"; // security if it allows trival reuse of discarded deviceDocs to access accounts...?
  58 + coux.put([cloudControl, deviceDoc._id], deviceDoc, e());
  59 + } // else we are done, applyOAuth had no work to do
  60 + }
  61 + }));
  62 + });
  63 + }
  64 +
  65 +
  66 +
  67 +
  68 +function sendEmail(hook, address, link, cb) {
  69 + var email = {
  70 + to : address,
  71 + from : "jchris@couchbase.com",
  72 + subject : 'Confirm Sync',
  73 + body : 'To sync your phone with the sharing server, click this link:\n\n'
  74 + + link
  75 + };
  76 + hook.emit("sendEmail", email)
  77 +// how do we get an ack that that email was delivered?
  78 + cb(false);
  79 +}
  80 +
  81 +
  82 +function ensureUserDoc(serverUrl, name, fun) {
  83 + var user_doc_id = "org.couchdb.user:"+name;
  84 + coux([serverUrl, "_users", user_doc_id], function(err, userDoc) {
  85 + if (err && err.error == 'not_found') {
  86 + fun(false, {
  87 + _id : user_doc_id,
  88 + type : "user",
  89 + name : name,
  90 + roles : []
  91 + });
  92 + } else if (err) {
  93 + console.log("ensureUserDoc Err", err.stack)
  94 + } else {
  95 + fun(false, userDoc);
  96 + }
  97 + });
  98 +}
  99 +
  100 +function applyOAuth(userDoc, deviceDoc, serverUrl, cb) {
  101 + var creds = deviceDoc.oauth_creds, id = deviceDoc._id;
  102 + if (!userDoc) {
  103 + userDoc = {};
  104 + }
  105 + if (!userDoc.oauth) {
  106 + userDoc.oauth = {
  107 + consumer_keys : {},
  108 + tokens : {}
  109 + };
  110 + }
  111 + if (!userDoc.oauth['devices']) {
  112 + userDoc.oauth['devices'] = {};
  113 + }
  114 + if (userDoc.oauth.consumer_keys[creds.consumer_key] || userDoc.oauth.tokens[creds.token]) {
  115 + if (userDoc.oauth.consumer_keys[creds.consumer_key] == creds.consumer_secret &&
  116 + userDoc.oauth.tokens[creds.token] == creds.token_secret &&
  117 + userDoc.oauth.devices[id][0] == creds.consumer_key &&
  118 + userDoc.oauth.devices[id][1] == creds.token) {
  119 + // no op, no problem
  120 + cb(false)
  121 + } else {
  122 + cb({error : "token_used", message : "device_id "+id})
  123 + }
  124 + }
  125 + userDoc.oauth.devices[id] = [creds.consumer_key, creds.token];
  126 + userDoc.oauth.consumer_keys[creds.consumer_key] = creds.consumer_secret;
  127 + userDoc.oauth.tokens[creds.token] = creds.token_secret;
  128 + // set the config that we need with oauth user doc capability
  129 + setOAuthConfig(userDoc, id, creds, serverUrl, cb);
  130 +};
  131 +
  132 +// assuming we are still running on a version of couch that doesn't have
  133 +// https://issues.apache.org/jira/browse/COUCHDB-1238 fixed
  134 +function setOAuthConfig(userDoc, id, creds, serverUrl, cb) {
  135 + var rc = 0, ops = [
  136 + ["oauth_consumer_secrets", creds.consumer_key, creds.consumer_secret],
  137 + ["oauth_token_users", creds.token, userDoc.name],
  138 + ["oauth_token_secrets", creds.token, creds.token_secret]
  139 + ];
  140 + for (var i=0; i < ops.length; i++) {
  141 + var op = ops[i];
  142 + coux.put([serverUrl, "_config", op[0], op[1]], op[2], function(err) {
  143 + if (err) {
  144 + cb(err)
  145 + } else {
  146 + rc += 1;
  147 + if (rc == ops.length) {
  148 + cb(false)
  149 + }
  150 + }
  151 + });
  152 + };
  153 +}

0 comments on commit 9c2fc70

Please sign in to comment.
Something went wrong with that request. Please try again.