beakerbrowser/hashbase

Logging in from Command Line

heyjordn opened this issue ยท 11 comments

Hi, Im trying to build a hashbase-cli around the api routes found here, however when attempting to do a POST to route /v1/login, I always seem to get a 403 forbidden response. Here's my code

const config = require("../../config/index");
const prompt = require("prompt");
const got = require("got");

  let username;
  let password;
  try {
    let result = await prompUser();
    //https://hashbase.io/v1/login
    response = await got.post(config.loginUser, {
      body: {
        username: result.username,
        password: result.password
      },
      json: true
    });
  } catch (error) {
    console.log("Error!");
    console.log(error);
  }

My JSON payload contains username and password but looking at the docs it expects email and password. As opposed to the source that expects username.

Whoops yeah, looks like the docs are wrong on that. I'll correct it in a moment.

Your usage looks correct to me. Here's the relevant test: https://github.com/beakerbrowser/hashbase/blob/master/test/users.js#L264

Thanks, that test was the next thing I viewed ๐Ÿ˜„ but, looking closer at the source you have csrf middleware enabled. From what I gathered, through testing, I'd need to pass csrf token in the x-csrf-token as well as in the body of POST request.
Here's what I've been using to try and get the csrf token.

"use strict";
var request = require("request");
var cookieJar = request.jar();
request = request.defaults({ jar: cookieJar });
var baseURL = "https://hashbase.io/v1";
const getCsrfFromCookie = cookie => {
  // Extracts csrf value from the following eg.
  //_csrf=KRw608J6zHkefwUvrRq-wRMx; Path=/;
  return cookie.substring(6, cookie.length - 8);
};
request(
  {
    url: baseURL + "/login",
    method: "GET",
    jar: cookieJar,
    followAllRedirects: true
  },
  function(error, httpResponse, body) {
    if (error) {
      console.error(error);
      return;
    }

    let cookies = cookieJar.getCookies(baseURL + "/login");
    let csrfToken = getCsrfFromCookie(String(cookies[0]));

    request(
      {
        method: "POST",
        url: baseURL + "/login",
        contentType: "application/json",
        headers: {
          "x-csrf-token": csrfToken
        },
        json: true,
        body: {
          username: "prx01m4",
          password: "*********",
          _csrf: csrfToken
        },
        followAllRedirects: true
      },
      function(error, httpResponse, body) {
        console.log(body);
        if (error) {
          console.error(error);
          return;
        }
      }
    );
  }
);

I'm wondering if I should just sent data as application/x-www-form-urlencoded instead of json

Oh brother- right, I forgot about that. That's a pain for you! You may have the right solution but I'll see if there's something cleaner that we can do.

I'd suggest you stay with JSON. I prefer that as an exchange format. If there's some feature that works differently by the encoding, we should change it.

Agreed, prefer using JSON, I'll do some more testing and let you know if anything changes. Thanks for the help ๐Ÿ˜„

@pr0x1m4 Based on the csurf's readme, it looks like you can pass the token as {_csrf:} in the body. See https://github.com/expressjs/csurf#value. That might be easier.

Extracting the token from the cookies is a pain. Maybe we should add a route like /v1/csrf which would fetch a token for API calls.

screen shot 2017-11-24 at 11 13 35 am

Whoops JK. Will look around for better options.

Thought that would've been a security issue too.
One thought might be to include an API key for each user account (or have them generate it) and send that in JSON body when logging in.

So a registered user might want to use cli to push archives instead of Web UI, he/she would first have to go to hashbase.io generate an unique API key, then configure hashbase-cli to use that to authenticate (along with username and password)

According to https://github.com/pillarjs/understanding-csrf, if we disable CORS on effectful methods and and only accept JSON on those same methods, then we don't need CRSF.

So, one option would be to disable CORS and then either stop using urlencoded, or just require CSRF on urlencoded.

Ok great, so what would be the next steps? I could would more than willing to work getting that feature done in order to facilitate the cli. Would we just disable CORS on just api routes like /v1/login etc..

That would make sense. We need to double check that the hashbase frontend would still work.

Action items:

  • Disable CORS and disable urlencoded submissions to the API routes
  • Disable CSRF on the API routes
  • Make sure the frontend still works

Ok, going to deploy the update on the live service. LMK if everything is ๐Ÿ‘