insomnia/app/lib/export/curl.js
Gregory Schier 9e84bc4387 Workspaces, Cookies, and More! (#31)
* Start on workspace dropdown and upgrade fontawesome

* WorkspaceDropdown start and Elm components!

* Lots of CSS shit

* Refactor some db stuff and move filter out of sidebar

* Adjust dropdown css

* Handle duplicate header names, and stuff

* Shitty cookies tab

* fixed cookie table a bit

* Modal refactor

* Starteed cookie modal design

* Better cookie storage and filter cookie modal

* Cookie editor round 1

* Fix kve cursor jumping and form encoding templating

* New cookies now show up in filter

* Checkpoint

* Stuff and fix environments css

* Added manage cookies button to cookie pane

* Fix accidental sidebar item drag on sidebar resize

* Environments modal is looking pretty good now

* Pretty much done environments nad cookies

* Some changes

* Fixed codemirror in modals

* Fixed some things

* Add basic proxy support

* Updated shortcuts

* Code snippet generation

* Some style

* bug fix

* Code export now gets cookies for correct domain
2016-08-15 10:04:36 -07:00

199 lines
5.3 KiB
JavaScript

'use strict';
import render from '../render';
import * as querystring from '../querystring';
import * as db from '../../database';
import {DEBOUNCE_MILLIS, METHOD_GET} from '../constants';
import {getRenderedRequest} from '../render';
const FLAGS = [
'cacert', 'capath', 'E', 'cert', 'cert-type', 'ciphers', 'K', 'config',
'connect-timeout', 'C', 'continue-at', 'b',
'cookie', // TODO: Handle this
'c', 'cookie-jar', 'crlfile', 'd', 'data', 'data-ascii', 'data-binary',
'data-urlencode', 'delegation', 'D', 'dump-header', 'egd-file',
'engine', 'F', 'form', 'form-string', 'ftp-account', 'ftp-method',
'ftp-port', 'H', 'header', 'hostpubmd5', 'interface', 'keepalive-time',
'key', 'key-type', 'krb', 'lib-curl', 'limit-rate', 'local-port',
'mail-from', 'mail-rcpt', 'mail-auth', 'max-filesize', 'max-redirs',
'max-time', 'netrtc-file', 'output', 'pass', 'proto', 'proto-redir',
'proxy', 'proxy-user', 'proxy1.0', 'pubkey', 'Q', 'quote',
'random-file', 'range', 'X', 'request', 'resolve', 'retry',
'retry-delay', 'retry-max-time', 'socks4', 'socks4a', 'socks5',
'socks5-hostname', 'socks5-gssapi-service', 'Y', 'speed-limit',
'y', 'speed-time', 'stderr', 'tftp-blksize', 'z', 'time-cond', 'trace',
'trace-ascii', 'T', 'upload-file',
'url', // TODO: Handle this
'u', 'user', 'tlsuser', 'tlspassword', 'tlsauthtype',
'A', 'user-agent', // TODO: Handle this
'w', 'write-out'
];
const FLAG_REGEXES = [
/\s--([\w\-]{2,})\s+"((?:[^"\\]|\\.)*)"/, // --my-flag "hello"
/\s--([\w\-]{2,})\s+'((?:[^'\\]|\\.)*)'/, // --my-flag 'hello'
/\s--([\w\-]{2,})\s+([^\s]+)/, // --my-flag hello
/\s-([\w])\s*'((?:[^'\\]|\\.)*)'/, // -X 'hello'
/\s-([\w])\s*"((?:[^"\\]|\\.)*)"/, // -X "hello"
/\s-([\w])\s*([^\s]+)/, // -X hello
/\s--([\w\-]+)/ // --switch (cleanup at the end)
];
function getFlags (cmd) {
const flags = {};
const switches = {};
for (var i = 0; i < FLAG_REGEXES.length; i++) {
var matches = [];
var match;
var key;
var val;
var matchedFlag;
// Stop at 1000 to prevent infinite loops
// TODO: Make this recursive
for (var j = 0; (matches = FLAG_REGEXES[i].exec(cmd)); j++) {
if (j > 1000) {
console.error('INFINITE LOOP');
break;
}
match = matches[0];
key = matches[1];
val = matches[2];
matchedFlag = !!val;
if (matchedFlag) {
if (isFlag(key)) {
// Matched a flag
flags[key] = flags[key] || [];
flags[key].push(val);
cmd = cmd.replace(match, '');
} else {
// Matched a flag that was actually a switch
cmd = cmd.replace('--' + key, '');
}
} else {
// Matched a switch directly without a value
switches[key] = true;
cmd = cmd.replace(match, '');
}
}
}
return {cmd, flags, switches};
}
function isFlag (key) {
for (var i = 0; i < FLAGS.length; i++) {
if (key === FLAGS[i]) {
return true;
}
}
return false;
}
function splitHeaders (flags) {
var headers = (flags['H'] || []).concat(flags['header'] || []);
var parsed = [];
for (var i = 0; i < headers.length; i++) {
var header = headers[i].split(':');
var name = header[0].trim();
var value = header[1].trim();
parsed.push({name: name, value: value});
}
return parsed;
}
function getContentType (headers) {
for (var i = 0; i < headers.length; i++) {
var header = headers[i];
if (header.name.toLowerCase() === 'content-type') {
return header.value;
}
}
return null;
}
function getHttpMethod (flags, hasBody) {
var method = (flags['X'] || flags['request'] || [])[0];
// If there is no method specified, but there is a body, default
// to POST, else default to GET
if (!method) {
method = hasBody ? 'POST' : 'GET';
}
return method;
}
function getBasicAuth (flags) {
var authString = flags.u || flags.user;
var auth = {
username: '',
password: ''
};
if (authString) {
var authSplit = authString[0].split(':');
auth.username = (authSplit[0] || '').trim();
auth.password = (authSplit[1] || '').trim();
}
return auth;
}
export function importCurl (blob) {
if (!blob || blob.toLowerCase().indexOf('curl ') !== 0) {
return false;
}
// Rip out the flags
let {cmd, flags, switches} = getFlags(blob);
// Final values
const headers = splitHeaders(flags);
let body = (
flags.d ||
flags.data ||
flags['data-binary'] ||
flags['data-ascii'] ||
[]
)[0] || '';
const contentType = getContentType(headers) || null;
if (contentType.toLowerCase() === 'application/json') {
try {
body = JSON.stringify(JSON.parse(body), null, '\t');
} catch (e) {
}
}
const httpMethod = getHttpMethod(flags, !!body);
const authentication = getBasicAuth(flags);
// Clean up the remaining URL
cmd = (cmd + ' ')
.replace(/\\ /g, ' ').replace(/ \\/g, ' ') // slashes
.replace(/\s/g, ' ') // whitespaces
.replace(/ "/g, ' ').replace(/" /g, ' ') // double-quotes
.replace(/ '/g, ' ').replace(/' /g, ' '); // single-quotes
const url = /curl\s+['"]?((?!('|")).*)['"]?/.exec(cmd)[1].trim();
return {
url: url,
body: body,
headers: headers,
contentType: contentType,
method: httpMethod,
authentication: authentication
};
}