// Generated by IcedCoffeeScript 1.7.1-c
(function() {
  var C, E, Leaf, MerkleClient, a_json_parse, athrow, createHash, db, env, iced, kbpgp, keys, log, make_esc, master_ring, pathcheck, req, __iced_k, __iced_k_noop, _merkle_client, _ref,
    __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };

  iced = require('iced-runtime').iced;
  __iced_k = __iced_k_noop = function() {};

  db = require('./db');

  req = require('./req');

  log = require('./log');

  E = require('./err').E;

  make_esc = require('iced-error').make_esc;

  _ref = require('iced-utils').util, a_json_parse = _ref.a_json_parse, athrow = _ref.athrow;

  createHash = require('crypto').createHash;

  master_ring = require('./keyring').master_ring;

  keys = require('./keys');

  env = require('./env').env;

  C = require('./constants').constants;

  pathcheck = require('libkeybase').merkle.pathcheck;

  Leaf = require('libkeybase').merkle.leaf.Leaf;

  kbpgp = require('kbpgp');

  MerkleClient = (function() {
    MerkleClient.LATEST = "latest";

    function MerkleClient() {
      this._nodes = {};
      this._keys = {};
      this._verified = {};
    }

    MerkleClient.prototype.lookup_path = function(_arg, cb) {
      var uid, username;
      uid = _arg.uid, username = _arg.username;
      if ((uid == null) && (username == null)) {
        cb(new Error("lookup_path: one of uid or username must be specified"));
        return;
      }
      if ((uid != null) && (username != null)) {
        cb(new Error("lookup_path: only one of uid (" + uid + ") and username (" + username + ") can be specified"));
        return;
      }
      return req.get({
        endpoint: "merkle/path",
        args: {
          uid: uid,
          username: username
        }
      }, cb);
    };

    MerkleClient.prototype.check_key_fingerprint = function(_arg, cb) {
      var err, fingerprint;
      fingerprint = _arg.fingerprint;
      if (__indexOf.call(env().get_merkle_key_fingerprints(), fingerprint) >= 0) {
        err = null;
      } else {
        err = new E.KeyNotTrustedError("the fingerprint " + fingerprint + " isn't trusted");
      }
      return cb(err);
    };

    MerkleClient.prototype.find_key_data = function(_arg, cb) {
      var err, fingerprint, json, key_data, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      fingerprint = _arg.fingerprint;
      err = key_data = null;
      (function(_this) {
        return (function(__iced_k) {
          if ((key_data = keys.lookup[fingerprint]) == null) {
            (function(__iced_k) {
              __iced_deferrals = new iced.Deferrals(__iced_k, {
                parent: ___iced_passed_deferral,
                filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
                funcname: "MerkleClient.find_key_data"
              });
              req.get({
                endpoint: "key/special",
                args: {
                  fingerprint: fingerprint
                }
              }, __iced_deferrals.defer({
                assign_fn: (function() {
                  return function() {
                    err = arguments[0];
                    return json = arguments[1];
                  };
                })(),
                lineno: 53
              }));
              __iced_deferrals._fulfill();
            })(function() {
              return __iced_k(err != null ? void 0 : (key_data = json.bundle) == null ? err = new E.KeyNotFoundError("have no key for " + fingerprint) : void 0);
            });
          } else {
            return __iced_k();
          }
        });
      })(this)((function(_this) {
        return function() {
          return cb(err, key_data);
        };
      })(this));
    };

    MerkleClient.prototype.get_merkle_pgp_key = function(_arg, cb) {
      var err, esc, fingerprint, index, key_data, obj, ret, ring, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      fingerprint = _arg.fingerprint;
      ring = master_ring();
      esc = make_esc(cb, "MerkleClient::get_merkle_pgp_key");
      err = ret = null;
      log.debug("+ merkle get_merkle_pgp_key");
      (function(_this) {
        return (function(__iced_k) {
          if ((ret = _this._keys[fingerprint]) == null) {
            (function(__iced_k) {
              __iced_deferrals = new iced.Deferrals(__iced_k, {
                parent: ___iced_passed_deferral,
                filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
                funcname: "MerkleClient.get_merkle_pgp_key"
              });
              ring.index2({}, esc(__iced_deferrals.defer({
                assign_fn: (function() {
                  return function() {
                    return index = arguments[0];
                  };
                })(),
                lineno: 67
              })));
              __iced_deferrals._fulfill();
            })(function() {
              var _ref1;
              _ref1 = index.lookup().fingerprint.get_0_or_1(fingerprint), err = _ref1[0], obj = _ref1[1];
              (function(__iced_k) {
                if (err != null) {
                  return __iced_k();
                } else {
                  (function(__iced_k) {
                    if (obj != null) {
                      log.debug("| merkle key already found in keyring");
                      return __iced_k(ret = ring.make_key({
                        fingerprint: fingerprint
                      }));
                    } else {
                      (function(__iced_k) {
                        __iced_deferrals = new iced.Deferrals(__iced_k, {
                          parent: ___iced_passed_deferral,
                          filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
                          funcname: "MerkleClient.get_merkle_pgp_key"
                        });
                        _this.find_key_data({
                          fingerprint: fingerprint
                        }, esc(__iced_deferrals.defer({
                          assign_fn: (function() {
                            return function() {
                              return key_data = arguments[0];
                            };
                          })(),
                          lineno: 74
                        })));
                        __iced_deferrals._fulfill();
                      })(function() {
                        log.debug("| doing a merkle key import for " + fingerprint);
                        ret = ring.make_key({
                          fingerprint: fingerprint,
                          key_data: key_data
                        });
                        (function(__iced_k) {
                          __iced_deferrals = new iced.Deferrals(__iced_k, {
                            parent: ___iced_passed_deferral,
                            filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
                            funcname: "MerkleClient.get_merkle_pgp_key"
                          });
                          ret.save(esc(__iced_deferrals.defer({
                            lineno: 77
                          })));
                          __iced_deferrals._fulfill();
                        })(function() {
                          return __iced_k(ret = ring.make_key({
                            fingerprint: fingerprint
                          }));
                        });
                      });
                    }
                  })(__iced_k);
                }
              })(function() {
                return __iced_k(ret != null ? _this._keys[fingerprint] = ret : void 0);
              });
            });
          } else {
            return __iced_k();
          }
        });
      })(this)((function(_this) {
        return function() {
          log.debug("- merkle get_merkle_pgp_key");
          return cb(err, ret);
        };
      })(this));
    };

    MerkleClient.prototype.rollback_check = function(_arg, cb) {
      var err, esc, last_root, p, q, root, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      root = _arg.root;
      log.debug("+ Rollback check");
      esc = make_esc(cb, "MerkleClient::rollback_check");
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
            funcname: "MerkleClient.rollback_check"
          });
          _this.load_last_root(esc(__iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                return last_root = arguments[0];
              };
            })(),
            lineno: 90
          })));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          err = null;
          (function(__iced_k) {
            var _ref1, _ref2;
            if ((typeof last_root !== "undefined" && last_root !== null) && (((q = (_ref1 = last_root.payload.body) != null ? _ref1.seqno : void 0) == null) || q > (p = (_ref2 = root.payload.body) != null ? _ref2.seqno : void 0))) {
              return __iced_k(err = new E.VersionRollbackError("Merkle root version rollback detected: " + q + " > " + p));
            } else {
              (function(__iced_k) {
                __iced_deferrals = new iced.Deferrals(__iced_k, {
                  parent: ___iced_passed_deferral,
                  filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
                  funcname: "MerkleClient.rollback_check"
                });
                _this.store_this_root({
                  root: root
                }, esc(__iced_deferrals.defer({
                  lineno: 95
                })));
                __iced_deferrals._fulfill();
              })(__iced_k);
            }
          })(function() {
            log.debug("- Rollback check");
            return cb(err);
          });
        };
      })(this));
    };

    MerkleClient.prototype.store_this_root = function(_arg, cb) {
      var err, root, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      root = _arg.root;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
            funcname: "MerkleClient.store_this_root"
          });
          db.put({
            type: C.ids.merkle_root,
            key: root.hash,
            value: root,
            name: {
              type: C.lookups.merkle_root,
              name: MerkleClient.LATEST
            },
            debug: true
          }, __iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                return err = arguments[0];
              };
            })(),
            lineno: 111
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          return cb(err);
        };
      })(this));
    };

    MerkleClient.prototype.load_last_root = function(cb) {
      var err, obj, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
            funcname: "MerkleClient.load_last_root"
          });
          db.lookup({
            type: C.lookups.merkle_root,
            name: MerkleClient.LATEST
          }, __iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                err = arguments[0];
                return obj = arguments[1];
              };
            })(),
            lineno: 117
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          return cb(err, obj);
        };
      })(this));
    };

    MerkleClient.prototype.get_merkle_key_manager = function(_arg, cb) {
      var armored, blob, esc, fingerprint, key_manager, kid, path_response, pgp_key, ___iced_passed_deferral, __iced_deferrals, __iced_k, _ref1;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      path_response = _arg.path_response;
      esc = make_esc(cb, "MerkleClient::get_merkle_key_manager");
      fingerprint = null;
      _ref1 = path_response.root.sigs;
      for (kid in _ref1) {
        blob = _ref1[kid];
        if (blob.fingerprint != null) {
          fingerprint = blob.fingerprint;
          break;
        }
      }
      (function(_this) {
        return (function(__iced_k) {
          if (fingerprint == null) {
            (function(__iced_k) {
              __iced_deferrals = new iced.Deferrals(__iced_k, {
                parent: ___iced_passed_deferral,
                filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
                funcname: "MerkleClient.get_merkle_key_manager"
              });
              athrow(new Error("Didn't find a PGP fingerprint among the merkle sigs."), esc(__iced_deferrals.defer({
                lineno: 130
              })));
              __iced_deferrals._fulfill();
            })(__iced_k);
          } else {
            return __iced_k();
          }
        });
      })(this)((function(_this) {
        return function() {
          (function(__iced_k) {
            __iced_deferrals = new iced.Deferrals(__iced_k, {
              parent: ___iced_passed_deferral,
              filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
              funcname: "MerkleClient.get_merkle_key_manager"
            });
            _this.check_key_fingerprint({
              fingerprint: fingerprint
            }, esc(__iced_deferrals.defer({
              lineno: 131
            })));
            __iced_deferrals._fulfill();
          })(function() {
            (function(__iced_k) {
              __iced_deferrals = new iced.Deferrals(__iced_k, {
                parent: ___iced_passed_deferral,
                filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
                funcname: "MerkleClient.get_merkle_key_manager"
              });
              _this.get_merkle_pgp_key({
                fingerprint: fingerprint
              }, esc(__iced_deferrals.defer({
                assign_fn: (function() {
                  return function() {
                    return pgp_key = arguments[0];
                  };
                })(),
                lineno: 132
              })));
              __iced_deferrals._fulfill();
            })(function() {
              (function(__iced_k) {
                __iced_deferrals = new iced.Deferrals(__iced_k, {
                  parent: ___iced_passed_deferral,
                  filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
                  funcname: "MerkleClient.get_merkle_key_manager"
                });
                pgp_key.load(esc(__iced_deferrals.defer({
                  lineno: 133
                })));
                __iced_deferrals._fulfill();
              })(function() {
                armored = pgp_key.key_data();
                (function(__iced_k) {
                  __iced_deferrals = new iced.Deferrals(__iced_k, {
                    parent: ___iced_passed_deferral,
                    filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
                    funcname: "MerkleClient.get_merkle_key_manager"
                  });
                  kbpgp.KeyManager.import_from_armored_pgp({
                    armored: armored
                  }, esc(__iced_deferrals.defer({
                    assign_fn: (function() {
                      return function() {
                        return key_manager = arguments[0];
                      };
                    })(),
                    lineno: 135
                  })));
                  __iced_deferrals._fulfill();
                })(function() {
                  return cb(null, key_manager);
                });
              });
            });
          });
        };
      })(this));
    };

    MerkleClient.prototype.get_root_with_parsed_payload = function(_arg, cb) {
      var esc, k, payload, root_clone, root_from_server, v, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      root_from_server = _arg.root_from_server;
      esc = make_esc(cb, "MerkleClient::get_root_with_parsed_payload");
      root_clone = {};
      for (k in root_from_server) {
        v = root_from_server[k];
        root_clone[k] = v;
      }
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
            funcname: "MerkleClient.get_root_with_parsed_payload"
          });
          a_json_parse(root_clone.payload_json, esc(__iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                return payload = arguments[0];
              };
            })(),
            lineno: 146
          })));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          root_clone.payload_json = null;
          root_clone.payload = payload;
          return cb(null, root_clone);
        };
      })(this));
    };

    MerkleClient.prototype.find_and_verify = function(_arg, cb) {
      var esc, km, path_response, pathcheck_result, root, uid, username, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      uid = _arg.uid, username = _arg.username;
      esc = make_esc(cb, "MerkleClient::find_and_verify");
      username = username.toLowerCase();
      log.debug("+ merkle find_and_verify: uid " + uid + ", username " + username);
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
            funcname: "MerkleClient.find_and_verify"
          });
          _this.lookup_path({
            uid: uid,
            username: username
          }, esc(__iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                return path_response = arguments[0];
              };
            })(),
            lineno: 157
          })));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          (function(__iced_k) {
            __iced_deferrals = new iced.Deferrals(__iced_k, {
              parent: ___iced_passed_deferral,
              filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
              funcname: "MerkleClient.find_and_verify"
            });
            _this.get_merkle_key_manager({
              path_response: path_response
            }, esc(__iced_deferrals.defer({
              assign_fn: (function() {
                return function() {
                  return km = arguments[0];
                };
              })(),
              lineno: 158
            })));
            __iced_deferrals._fulfill();
          })(function() {
            (function(__iced_k) {
              __iced_deferrals = new iced.Deferrals(__iced_k, {
                parent: ___iced_passed_deferral,
                filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
                funcname: "MerkleClient.find_and_verify"
              });
              pathcheck({
                server_reply: path_response,
                km: km
              }, esc(__iced_deferrals.defer({
                assign_fn: (function() {
                  return function() {
                    return pathcheck_result = arguments[0];
                  };
                })(),
                lineno: 159
              })));
              __iced_deferrals._fulfill();
            })(function() {
              (function(__iced_k) {
                if ((uid != null) && pathcheck_result.uid !== uid) {
                  (function(__iced_k) {
                    __iced_deferrals = new iced.Deferrals(__iced_k, {
                      parent: ___iced_passed_deferral,
                      filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
                      funcname: "MerkleClient.find_and_verify"
                    });
                    athrow(new Error("Expected uid " + uid + " does not match merkle response uid " + pathcheck_result.uid), esc(__iced_deferrals.defer({
                      lineno: 161
                    })));
                    __iced_deferrals._fulfill();
                  })(__iced_k);
                } else {
                  return __iced_k();
                }
              })(function() {
                (function(__iced_k) {
                  if ((username != null) && pathcheck_result.username !== username) {
                    (function(__iced_k) {
                      __iced_deferrals = new iced.Deferrals(__iced_k, {
                        parent: ___iced_passed_deferral,
                        filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
                        funcname: "MerkleClient.find_and_verify"
                      });
                      athrow(new Error("Expected username " + username + " does not match merkle response username " + pathcheck_result.username), esc(__iced_deferrals.defer({
                        lineno: 163
                      })));
                      __iced_deferrals._fulfill();
                    })(__iced_k);
                  } else {
                    return __iced_k();
                  }
                })(function() {
                  (function(__iced_k) {
                    __iced_deferrals = new iced.Deferrals(__iced_k, {
                      parent: ___iced_passed_deferral,
                      filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
                      funcname: "MerkleClient.find_and_verify"
                    });
                    _this.get_root_with_parsed_payload({
                      root_from_server: path_response.root
                    }, esc(__iced_deferrals.defer({
                      assign_fn: (function() {
                        return function() {
                          return root = arguments[0];
                        };
                      })(),
                      lineno: 164
                    })));
                    __iced_deferrals._fulfill();
                  })(function() {
                    (function(__iced_k) {
                      __iced_deferrals = new iced.Deferrals(__iced_k, {
                        parent: ___iced_passed_deferral,
                        filename: "/Users/max/src/keybase/node-client/src/merkle_client.iced",
                        funcname: "MerkleClient.find_and_verify"
                      });
                      _this.rollback_check({
                        root: root
                      }, esc(__iced_deferrals.defer({
                        lineno: 165
                      })));
                      __iced_deferrals._fulfill();
                    })(function() {
                      return cb(null, pathcheck_result.leaf, root, path_response.id_version);
                    });
                  });
                });
              });
            });
          });
        };
      })(this));
    };

    return MerkleClient;

  })();

  _merkle_client = null;

  exports.merkle_client = function() {
    if (_merkle_client == null) {
      _merkle_client = new MerkleClient();
    }
    return _merkle_client;
  };

}).call(this);
