<commit_before>'use strict';
let api = require('./shared.js');
let cli = require('heroku-cli-util');
let net = require('net');
let parser = require('ioredis/lib/parsers/javascript.js');
let readline = require('readline');
let tls = require('tls');
let url = require('url');
let Client = require('ssh2').Client;

const REPLY_OK = 'OK';

function redisCLI(uri, client) {
  let io = readline.createInterface(process.stdin, process.stdout);
  let reply = new parser();
  let state = 'connect';

  client.write(`AUTH ${uri.auth.split(':')[1]}\n`);

  io.setPrompt(uri.host + '> ');

  reply.on('reply', function (reply) {
    switch (state) {
    case 'monitoring':
      if (reply !== REPLY_OK) {
        console.log(reply);
      }
      break;
    case 'subscriber':
      if (Array.isArray(reply)) {
        reply.forEach(function (value, i) {
          console.log(`${i+1}) ${value}`);
        });
      } else {
        console.log(reply);
      }
      break;
    case 'connect':
      if (reply !== REPLY_OK) {
        console.log(reply);
      }
      state = 'normal';
      io.prompt();
      break;
    case 'closing':
      if (reply !== REPLY_OK) {
        console.log(reply);
      }
      break;
    default:
      if (Array.isArray(reply)) {
        reply.forEach(function (value, i) {
          console.log(`${i+1}) ${value}`);
        });
      } else {
        console.log(reply);
      }
      io.prompt();
      break;
    }
  });
  reply.on('reply error', function (reply) {
    console.log(reply.message);
    io.prompt();
  });
  reply.on('error', function (err) {
    client.emit('error', err);
  });
  io.on('line', function (line) {
    switch (line.split(' ')[0]) {
    case 'MONITOR':
      state = 'monitoring';
      break;
    case 'PSUBSCRIBE':
    case 'SUBSCRIBE':
      state = 'subscriber';
      break;
    }
    client.write(`${line}\n`);
  });
  io.on('close', function () {
    state = 'closing';
    client.write('QUIT\n');
  });
  client.on('data', function (data) {
    reply.execute(data);
  });
  client.on('error', function(error) {
    cli.error(error);
    process.exit(1);
  });
  client.on('end', function () {
    console.log('\nDisconnected from instance.');
    process.exit(0);
  });
}

function match(config, lookup) {
  for (var key in config) {
    if (lookup.test(key)) {
      return config[key];
    }
  }
  return null;
}

function maybeTunnel(redis, config) {
  let bastions = match(config, /_BASTIONS/);
  let hobby = redis.plan.indexOf('hobby') == 0;
  let uri = url.parse(redis.resource_url);

  if (bastions != null) {
    let tunnel = new Client();
    tunnel.on('ready', function() {
      let localPort = Math.floor(Math.random() * (65535 - 49152) + 49152);
      tunnel.forwardOut('localhost', localPort, uri.hostname, uri.port, function(err, stream) {
        if (err) {
          cli.error(err);
        }
        stream.on('close', function() {
          tunnel.end();
        });
        redisCLI(uri, stream);
      });
    });
    tunnel.connect({
      host: bastions.split(',')[0],
      username: 'bastion',
      privateKey: match(config, /_BASTION_KEY/)
    });
  } else {
    let client;
    if (!hobby) {
      client = tls.connect({port: parseInt(uri.port, 10) + 1, host: uri.hostname, rejectUnauthorized: false});
    } else {
      client = net.connect({port: uri.port, host: uri.hostname});
    }
    redisCLI(uri, client);
  }
}

module.exports = {
  topic: 'redis',
  command: 'cli',
  needsApp: true,
  needsAuth: true,
  description: 'opens a redis prompt',
  args: [{name: 'database', optional: true}],
  run: cli.command({preauth: true}, function* (context, heroku) {
    let addonsFilter = api.make_addons_filter(context.args.database);
    let addonsList = heroku.apps(context.app).addons().listByApp();
    let addons = addonsFilter(yield addonsList);
    if (addons.length === 0) {
      cli.error('No Redis instances found.');
      process.exit(1);
    } else if (addons.length > 1) {
      let names = addons.map(function (addon) { return addon.name; });
      cli.error(`Please specify a single instance. Found: ${names.join(', ')}`);
      process.exit(1);
    }

    let config = yield heroku.apps(context.app).configVars().info();

    let addon = addons[0];
    let redis = yield api.request(context, addon.name);

    let vars = {};
    addon.config_vars.forEach(function (key) { vars[key] = config[key]; });

    console.log(`Connecting to ${addon.name} (${addon.config_vars.join(', ')}):`);
    maybeTunnel(redis, vars);
  })
};<commit_msg>Continue to warn hobby-dev users<commit_after>'use strict';
let api = require('./shared.js');
let cli = require('heroku-cli-util');
let net = require('net');
let parser = require('ioredis/lib/parsers/javascript.js');
let readline = require('readline');
let tls = require('tls');
let url = require('url');
let Client = require('ssh2').Client;

const REPLY_OK = 'OK';

function redisCLI(uri, client) {
  let io = readline.createInterface(process.stdin, process.stdout);
  let reply = new parser();
  let state = 'connect';

  client.write(`AUTH ${uri.auth.split(':')[1]}\n`);

  io.setPrompt(uri.host + '> ');

  reply.on('reply', function (reply) {
    switch (state) {
    case 'monitoring':
      if (reply !== REPLY_OK) {
        console.log(reply);
      }
      break;
    case 'subscriber':
      if (Array.isArray(reply)) {
        reply.forEach(function (value, i) {
          console.log(`${i+1}) ${value}`);
        });
      } else {
        console.log(reply);
      }
      break;
    case 'connect':
      if (reply !== REPLY_OK) {
        console.log(reply);
      }
      state = 'normal';
      io.prompt();
      break;
    case 'closing':
      if (reply !== REPLY_OK) {
        console.log(reply);
      }
      break;
    default:
      if (Array.isArray(reply)) {
        reply.forEach(function (value, i) {
          console.log(`${i+1}) ${value}`);
        });
      } else {
        console.log(reply);
      }
      io.prompt();
      break;
    }
  });
  reply.on('reply error', function (reply) {
    console.log(reply.message);
    io.prompt();
  });
  reply.on('error', function (err) {
    client.emit('error', err);
  });
  io.on('line', function (line) {
    switch (line.split(' ')[0]) {
    case 'MONITOR':
      state = 'monitoring';
      break;
    case 'PSUBSCRIBE':
    case 'SUBSCRIBE':
      state = 'subscriber';
      break;
    }
    client.write(`${line}\n`);
  });
  io.on('close', function () {
    state = 'closing';
    client.write('QUIT\n');
  });
  client.on('data', function (data) {
    reply.execute(data);
  });
  client.on('error', function(error) {
    cli.error(error);
    process.exit(1);
  });
  client.on('end', function () {
    console.log('\nDisconnected from instance.');
    process.exit(0);
  });
}

function match(config, lookup) {
  for (var key in config) {
    if (lookup.test(key)) {
      return config[key];
    }
  }
  return null;
}

function maybeTunnel(redis, config) {
  let bastions = match(config, /_BASTIONS/);
  let hobby = redis.plan.indexOf('hobby') == 0;
  let uri = url.parse(redis.resource_url);

  if (bastions != null) {
    let tunnel = new Client();
    tunnel.on('ready', function() {
      let localPort = Math.floor(Math.random() * (65535 - 49152) + 49152);
      tunnel.forwardOut('localhost', localPort, uri.hostname, uri.port, function(err, stream) {
        if (err) {
          cli.error(err);
        }
        stream.on('close', function() {
          tunnel.end();
        });
        redisCLI(uri, stream);
      });
    });
    tunnel.connect({
      host: bastions.split(',')[0],
      username: 'bastion',
      privateKey: match(config, /_BASTION_KEY/)
    });
  } else {
    let client;
    if (!hobby) {
      client = tls.connect({port: parseInt(uri.port, 10) + 1, host: uri.hostname, rejectUnauthorized: false});
    } else {
      client = net.connect({port: uri.port, host: uri.hostname});
    }
    redisCLI(uri, client);
  }
}

module.exports = {
  topic: 'redis',
  command: 'cli',
  needsApp: true,
  needsAuth: true,
  description: 'opens a redis prompt',
  args: [{name: 'database', optional: true}],
  flags: [{name: 'confirm', char: 'c', hasValue: true}],
  run: cli.command({preauth: true}, function* (context, heroku) {
    let addonsFilter = api.make_addons_filter(context.args.database);
    let addonsList = heroku.apps(context.app).addons().listByApp();
    let addons = addonsFilter(yield addonsList);
    if (addons.length === 0) {
      cli.error('No Redis instances found.');
      process.exit(1);
    } else if (addons.length > 1) {
      let names = addons.map(function (addon) { return addon.name; });
      cli.error(`Please specify a single instance. Found: ${names.join(', ')}`);
      process.exit(1);
    }

    let config = yield heroku.apps(context.app).configVars().info();

    let addon = addons[0];
    let redis = yield api.request(context, addon.name);
    let hobby = redis.plan.indexOf('hobby') == 0;

    if (hobby) {
      yield cli.confirmApp(context.app, context.flags.confirm, 'WARNING: Insecure action.\nAll data, including the Redis password, will not be encrypted.');
    }

    let vars = {};
    addon.config_vars.forEach(function (key) { vars[key] = config[key]; });

    console.log(`Connecting to ${addon.name} (${addon.config_vars.join(', ')}):`);
    maybeTunnel(redis, vars);
  })
};
{'fraction_non_alphanumeric': 0.18080238373949134, 'fraction_numerical': 0.00691710120251144, 'mean_word_length': 2.735294117647059, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4329521', 'n_tokens_mistral': 3236, 'n_tokens_neox': 3202, 'n_words': 672}