コード例 #1
0
ファイル: account.py プロジェクト: BlueSpaceCookie/blockchain
def get_or_create_username(config, machine_auth):
    """ Gets an existing username or creates a new account

        On a bitcoin computer a user can create one account per
        machine auth wallet. When not on a BC a user must log into
        an existing account created at the free signup page.

    Args:
        config (Config): config object used for getting .two1 information
        machine_auth (MachineAuthWallet): machine auth wallet used for authentication

    Returns:
        str: username of the current user on the system
    """
    # User hasn't logged in with the wallet
    if not config.mining_auth_pubkey:
        # A user can create an account on a BC
        if two1.TWO1_DEVICE_ID:
            login.create_account_on_bc(config, machine_auth)

        # log into an existing account
        else:
            login.login_account(config, machine_auth)

    if not config.username:
        raise exceptions.Two1Error(uxstring.UxString.Error.login_error_username)

    if not config.mining_auth_pubkey:
        exceptions.Two1Error(uxstring.UxString.Error.login_error_mining_auth_pubkey)

    return config.username
コード例 #2
0
ファイル: doctor.py プロジェクト: saakaifoundry/two1-python
def _doctor(two1_config):

    # warm welcome message
    logger.info(uxstring.UxString.doctor_start)

    # Get an appointment with the doctor
    doc = Doctor(two1_config)

    # Get a general doctor checkup
    doc.checkup("general")
    doc.checkup("dependency")
    doc.checkup("server")
    if bitcoin_computer.get_device_uuid():
        doc.checkup("BC")

    logger.info("\n" + uxstring.UxString.doctor_total)

    # groups all checks into one class for reuse of print_summary
    doc.print_results()

    if len(doc.get_checks(Check.Result.FAIL)) == 0:
        return doc.to_dict()
    else:
        raise exceptions.Two1Error("21 doctor failed some checks.",
                                   json=doc.to_dict())
コード例 #3
0
def buybitcoin_show_info(config, client, exchange):
    resp = client.get_coinbase_status()
    if not resp.ok:
        raise exceptions.Two1Error("Failed to get exchange status")

    coinbase = resp.json().get("coinbase")

    if not coinbase:
        # Not linked, prompt user to info
        return buybitcoin_config(config, client, exchange)
    else:
        payment_method_string = click.style("No Payment Method linked yet.", fg="red", bold=True)
        if coinbase["payment_method"] is not None:
            payment_method_string = coinbase["payment_method"]["name"]

        logger.info(uxstring.UxString.exchange_info_header)
        logger.info(uxstring.UxString.exchange_info.format(exchange.capitalize(), coinbase["name"],
                                                           coinbase["account_name"], payment_method_string))
        if coinbase["payment_method"] is None:
            ADD_PAYMENT_METHOD_URL = "https://coinbase.com/quickstarts/payment"
            logger.info(uxstring.UxString.buybitcoin_no_payment_method.format(
                exchange.capitalize(),
                click.style(ADD_PAYMENT_METHOD_URL, fg="blue", bold=True)
            ))
        else:
            logger.info(uxstring.UxString.buybitcoin_instruction_header)
            logger.info(uxstring.UxString.buybitcoin_instructions.format(exchange.capitalize()))
        return coinbase
コード例 #4
0
def get_price_quote(client, amount):
    # first get a quote
    try:
        resp = client.buy_bitcoin_from_exchange(amount, "satoshis", commit=False)
    except exceptions.ServerRequestError as e:
        if e.status_code == 400:
            if e.data.get("error") == "TO700":
                logger.info(uxstring.UxString.minimum_bitcoin_purchase)
            elif e.data.get("error") == "TO704":
                logger.info(uxstring.UxString.coinbase_amount_too_high)
            raise ValueError()
        elif e.status_code == 403:
            if e.data.get("error") == "TO703":
                logger.info(uxstring.UxString.coinbase_max_buy_reached)
            raise ValueError()

    buy_result = resp.json()
    if "err" in buy_result:
        logger.info(uxstring.UxString.buybitcoin_error.format(
            click.style(buy_result["err"], bold=True, fg="red")))
        raise exceptions.Two1Error("Failed to execute buybitcoin {} {}".format(amount, "satoshis"))

    fees = buy_result["fees"]
    total_fees = ["{:.2f} {} {} {}".format(
                  float(fee["amount"]["amount"]), fee["amount"]["currency"],
                  "fee from your" if fee["type"] == "bank" else "fee from",
                  "Coinbase" if fee["type"] == "coinbase" else fee["type"])
                  for fee in fees]
    total_fees = click.style(" and ".join(total_fees), bold=True)
    total_amount = buy_result["total"]
    total = click.style("{} {}".format(total_amount["amount"], total_amount["currency"]), bold=True)
    bitcoin_amount = click.style("{} {}".format(int(amount), "satoshis"), bold=True)

    logger.info(uxstring.UxString.buybitcoin_confirmation.format(total, bitcoin_amount, total, total_fees))
コード例 #5
0
def parse_config(
    config_file=two1.TWO1_CONFIG_FILE,
    config_dict=None,
    need_wallet_and_account=True,
    check_update=False,
    debug=False,
):
    """Get configuration information that is used to drive all 21 commands.

    This function is very useful for testing as it builds up several
    key variables (like the client, wallet, username, and the like)
    that are used in many commands. The way it does this is by taking
    in the config_file (typically .two1/two1.json) and the config_dict
    (a list of key-value pairs to override the config_file, typically
    an empty dictionary), and then running the logic below.

    It returns obj which is a dictionary that has Config, Wallet,
    MachineAuth, and TwentyOneRestClient instances underneath it, as
    well as a string with the username. The obj is passed down by
    click to various other commands.

    You can use this function in any test to instantiate the user's
    wallet, username, and other variables.
    """
    try:
        config = two1_config.Config(config_file,
                                    config_dict,
                                    check_update=check_update)
    except exceptions.FileDecodeError as e:
        raise click.ClickException(
            uxstring.UxString.Error.file_decode.format((str(e))))

    wallet, machine_auth, username, client = None, None, None, None
    if need_wallet_and_account:
        try:
            wallet = wallet_utils.get_or_create_wallet(config.wallet_path)
        except blockchain_exceptions.DataProviderError as err:
            raise exceptions.Two1Error(
                'You have experienced a data provider error: %s ' % err.args)
        machine_auth = machine_auth_wallet.MachineAuthWallet(wallet)
        username = account_utils.get_or_create_username(config, machine_auth)
        client = rest_client.TwentyOneRestClient(two1.TWO1_HOST, machine_auth,
                                                 config.username)
        config.username = username

    obj = dict(
        config=config,
        wallet=wallet,
        machine_auth=machine_auth,
        username=username,
        client=client,
        debug=debug,
    )
    return obj
コード例 #6
0
 def __init__(self, amount, denomination=SAT, rest_client=None):
     """Return a new Price object with the provided amount."""
     if amount < 0:
         raise exceptions.Two1Error(
             'Parameter `amount` must be a positive number.')
     if denomination.lower() in Price.SAT:
         self.denomination = Price.SAT
     elif denomination.lower() in Price.BTC:
         if amount < Price.SAT_TO_BTC:
             raise exceptions.Two1Error(
                 'Bitcoin amount must be larger than 1e-8')
         self.denomination = Price.BTC
     elif denomination.lower() in Price.USD:
         self.denomination = Price.USD
     else:
         raise exceptions.Two1Error(
             'Unknown denomination: {}.\nValid denominations: {}.'.format(
                 denomination, Price.DENOMINATIONS))
     self.amount = amount
     self.rest_client = rest_client if rest_client else create_default_rest_client(
     )
コード例 #7
0
ファイル: nginx.py プロジェクト: BlueSpaceCookie/blockchain
def create_systemd_file(dirname):
    """Create a systemd file that manages the starting/stopping
    of the gunicorn process.

    All processes are bound to a socket by default within the
    app directory.

    Args:
        dirname (string): directory the app is located in.

    Returns:
        bool: True if the process was successfully completed,
            False otherwise.
    """
    rv = False
    plat = detect_os()
    if "darwin" in plat:
        raise exceptions.Two1Error(uxstring.UxString.unsupported_platform)

    appdir = dir_to_absolute(dirname)
    appname = absolute_path_to_foldername(appdir)
    with tempfile.NamedTemporaryFile() as tf:
        systemd_file = """[Unit]
Description=gunicorn daemon for %s
After=network.target

[Service]
WorkingDirectory=%s
ExecStart=/usr/local/bin/gunicorn %s-server:app --workers 1 --bind unix:%s%s.sock --access-logfile %sgunicorn.access.log --error-logfile %sgunicorn.error.log

[Install]
WantedBy=default.target
        """ % (  # nopep8
            appname, appdir, appname, appdir, appname, appdir, appdir)
        tf.write(systemd_file.encode())
        tf.flush()
        try:
            subprocess.check_output([
                "sudo", "cp", tf.name,
                "/etc/systemd/user/{}.service".format(appname)
            ])
            subprocess.check_output([
                "sudo", "chmod", "644",
                "/etc/systemd/user/{}.service".format(appname)
            ])
            subprocess.check_output(['systemctl', '--user', 'enable', appname])
            subprocess.check_output(['systemctl', '--user', 'start', appname])
            rv = True
        except subprocess.CalledProcessError as e:
            raise e
    return rv
コード例 #8
0
def buybitcoin(ctx, info, amount, denomination, history, price):
    """Buy bitcoin through Coinbase.

\b
To use this command, you need to connect your 21 account with your Coinbase account.
You can find the instructions here: https://21.co/learn/21-buybitcoin/

\b
Quote the price of 100000 satoshis.
$ 21 buybitcoin 1000000 --price

\b
Buy 100000 satoshis from Coinbase.
$ 21 buybitcoin 100000 satoshis
You can use the following denominations: satoshis, bitcoins, and USD.

\b
Buy 5 dollars of bitcoin from Coinbase.
$ 21 buybitcoin 5 usd

\b
See history of your purchases.
$ 21 buybitcoin --history

\b
See the status of your 21 and Coinbase account integration.
$ 21 buybitcoin --info


The Bitcoins you purchase through this command will be deposited to
your local wallet.

If you have Instant Buy enabled on your Coinbase account, the purchase
will be immediate. If you don't have Instant Buy, it may take up to 5
days for the purchase to be completed.

    """
    exchange = "coinbase"
    if amount != 0.0:
        if denomination == '':
            confirmed = click.confirm(
                uxstring.UxString.default_price_denomination, default=True)
            if not confirmed:
                raise exceptions.Two1Error(uxstring.UxString.cancel_command)
            denomination = currency.Price.SAT
        amount = currency.Price(amount, denomination).satoshis
    return _buybitcoin(ctx, ctx.obj['config'], ctx.obj['client'], info,
                       exchange, amount, history, price, denomination)
コード例 #9
0
ファイル: nginx.py プロジェクト: BlueSpaceCookie/blockchain
def detect_os():
    """ Detect if the operating system
    that is running is either osx, debian-based
    or other.

    Returns:
        str: platform name

    Raises:
        OSError: if platform is not supported
    """
    plat = platform.system().lower()
    if plat in ['debian', 'linux']:
        return 'debian'
    elif 'darwin' in plat:
        return 'darwin'
    else:
        raise exceptions.Two1Error(uxstring.UxString.unsupported_platform)
コード例 #10
0
def buybitcoin_buy(config, client, exchange, amount):

    resp = client.get_coinbase_status()
    if not resp.ok:
        raise exceptions.Two1Error("Failed to get exchange status")

    coinbase = resp.json().get("coinbase")

    if not coinbase:
        return buybitcoin_config(config, client, exchange)

    try:
        get_price_quote(client, amount)
    except ValueError:
        return

    try:
        buy_bitcoin(client, amount)
    except click.exceptions.Abort:
        logger.info("\nPurchase canceled", fg="magenta")
コード例 #11
0
def convert_amount_to_satoshis_with_prompt(amount, denomination):
    """ Converts and amount with denomination to satoshis. Prompts user if no denomination is specified.
    Args:
        amount (float): representing the amount to flush
        denomination (str): One of [satoshis, bitcoins, usd]

    Returns (int): converted amount to satoshis.
    """
    if amount != 0.0:
        if denomination == '':
            confirmed = click.confirm(
                uxstring.UxString.default_price_denomination, default=True)
            if not confirmed:
                raise exceptions.Two1Error(uxstring.UxString.cancel_command)
            denomination = Price.SAT
        amount = Price(amount, denomination).satoshis
    else:
        amount = None

    return amount
コード例 #12
0
def buybitcoin_history(config, client, exchange):
    resp = client.get_coinbase_status()
    if not resp.ok:
        raise exceptions.Two1Error("Failed to get exchange status")

    coinbase = resp.json()["coinbase"]

    if not coinbase:
        # Not linked, prompt user to info
        return buybitcoin_config(config, client, exchange)
    else:
        resp = client.get_coinbase_history()
        history = resp.json()["history"]

        lines = [uxstring.UxString.coinbase_history_title]

        for entry in history:
            amount = entry["amount"]
            deposit_status = entry["deposit_status"]
            payout_time = util.format_date(entry["payout_time"])
            payout_address = entry["payout_address"]

            description = "N/A"
            if deposit_status == "COMPLETED":
                description = uxstring.UxString.coinbase_wallet_completed.format(
                    payout_time)
            else:
                description = uxstring.UxString.coinbase_wallet_pending.format(
                    payout_time)

            created = util.format_date(entry["created"])
            lines.append(
                uxstring.UxString.coinbase_history.format(
                    created, amount, payout_address, description))

        if len(history) == 0:
            lines.append(uxstring.UxString.coinbase_no_bitcoins_purchased)

        prints = "\n\n".join(lines)
        logger.info(prints, pager=True)
コード例 #13
0
def send(ctx, address, amount, denomination, use_unconfirmed, verbose):
    """Send a specified address some satoshis.

\b
Usage
-----
Send 5000 satoshi from your on-chain balance to the Apache Foundation.
$ 21 send 1BtjAzWGLyAavUkbw3QsyzzNDKdtPXk95D 5000 satoshis

You can use the following denominations: satoshis, bitcoins, and USD.

By default, this command uses only confirmed transactions and
UTXOs to send coins. To use unconfirmed transactions, use the
--use-unconfirmed flag.
"""
    if denomination == '':
        confirmed = click.confirm(uxstring.UxString.default_price_denomination,
                                  default=True)
        if not confirmed:
            raise exceptions.Two1Error(uxstring.UxString.cancel_command)
        denomination = currency.Price.SAT
    price = currency.Price(amount, denomination)
    return _send(ctx.obj['wallet'], address, price.satoshis, verbose,
                 use_unconfirmed)
コード例 #14
0
def _send(wallet, address, satoshis, verbose, use_unconfirmed=False):
    """Send bitcoin to the specified address"""
    txids = []
    try:
        txids = wallet.send_to(address=address,
                               amount=satoshis,
                               use_unconfirmed=use_unconfirmed)
        # For now there is only a single txn created, so assume it's 0
        txid, txn = txids[0]["txid"], txids[0]["txn"]
        if verbose:
            logger.info(
                uxstring.UxString.send_success_verbose.format(
                    satoshis, address, txid, txn))
        else:
            logger.info(
                uxstring.UxString.send_success.format(satoshis, address, txid))
    except ValueError as e:
        # This will trigger if there's a below dust-limit output.
        raise exceptions.Two1Error(str(e))
    except WalletBalanceError as e:
        if wallet.unconfirmed_balance() > satoshis:
            raise exceptions.Two1Error(
                uxstring.UxString.send_insufficient_confirmed + str(e))
        else:
            balance = min(wallet.confirmed_balance(),
                          wallet.unconfirmed_balance())
            if has_mining_chip():
                raise exceptions.Two1Error(
                    uxstring.UxString.send_insufficient_blockchain_21bc.format(
                        balance, satoshis, address))
            else:
                raise exceptions.Two1Error(
                    uxstring.UxString.send_insufficient_blockchain_free.format(
                        balance, satoshis, address))
    except DataProviderError as e:
        if "rejected" in str(e):
            raise exceptions.Two1Error(uxstring.UxString.send_rejected)
        else:
            raise exceptions.Two1Error(str(e))
    return txids
コード例 #15
0
ファイル: login.py プロジェクト: genavarov/Blockshare-Web-App
def create_account_on_bc(config, machine_auth):
    """ Creates an account for the current machine auth wallet

    Args:
        config (Config): config object used for getting .two1 information
        machine_auth (MachineAuthWallet): machine auth wallet used for authentication
    """
    # get the payout address and the pubkey from the machine auth wallet
    machine_auth_pubkey_b64 = base64.b64encode(machine_auth.public_key.compressed_bytes).decode()
    payout_address = machine_auth.wallet.current_address

    # Don't attempt to create an account if the user indicates they
    # already have an account (defaults to No)
    if click.confirm(uxstring.UxString.already_have_account):
        logger.info(uxstring.UxString.please_login)
        sys.exit()

    logger.info(uxstring.UxString.missing_account)
    email = None
    username = None
    fullname = None
    while True:
        if not fullname:
            fullname = click.prompt(uxstring.UxString.enter_name)

        if not email:
            email = click.prompt(uxstring.UxString.enter_email, type=EmailAddress())

        # prompts for a username and password
        if not username:
            try:
                logger.info("")
                username = click.prompt(uxstring.UxString.enter_username, type=Username())
                logger.info("")
                logger.info(uxstring.UxString.creating_account.format(username))
                password = click.prompt(uxstring.UxString.set_new_password.format(username),
                                        hide_input=True, confirmation_prompt=True, type=Password())
            except click.Abort:
                return

        try:
            # change the username of the given username
            rest_client = _rest_client.TwentyOneRestClient(two1.TWO1_HOST, machine_auth, username)
            rest_client.account_post(payout_address, email, password, fullname)

        # Do not continue creating an account because the UUID is invalid
        except exceptions.BitcoinComputerNeededError:
            raise

        except exceptions.ServerRequestError as ex:
            # handle various 400 errors from the server
            if ex.status_code == 400:
                if "error" in ex.data:
                    error_code = ex.data["error"]
                    # email exists
                    if error_code == "TO401":
                        logger.info(uxstring.UxString.email_exists.format(email))
                        email = None
                        continue
                    # username exists
                    elif error_code == "TO402":
                        logger.info(uxstring.UxString.username_exists.format(username))
                        username = None
                        continue
                # unexpected 400 error
                else:
                    raise exceptions.Two1Error(
                        str(next(iter(ex.data.values()), "")) + "({})".format(ex.status_code))

            # handle an invalid username format
            elif ex.status_code == 404:
                logger.info(uxstring.UxString.Error.invalid_username)
            # handle an error where a bitcoin computer is necessary
            elif ex.status_code == 403:
                r = ex.data
                if "detail" in r and "TO200" in r["detail"]:
                    raise exceptions.UnloggedException(uxstring.UxString.max_accounts_reached)
            else:
                logger.info(uxstring.UxString.Error.account_failed)
            username = None

        # created account successfully
        else:
            logger.info(uxstring.UxString.payout_address.format(payout_address))

            # save new username and password
            config.set("username", username)
            config.set("mining_auth_pubkey", machine_auth_pubkey_b64)
            config.save()

            break
コード例 #16
0
def _buy(config,
         client,
         machine_auth,
         resource,
         info_only=False,
         payment_method='offchain',
         header=(),
         method='GET',
         output_file=None,
         data=None,
         data_file=None,
         maxprice=10000,
         mock_requests=False):
    """Purchase a 402-enabled resource via CLI.

    This function attempts to purchase the requested resource using the
    `payment_method` and then write out its results to STDOUT. This allows a
    user to view results or pipe them into another command-line function.

    Args:
        config (two1.commands.config.Config): an object necessary for various
            user-specific actions, as well as for using the `capture_usage`
            function decorator.
        client (two1.server.rest_client.TwentyOneRestClient) an object for
            sending authenticated requests to the TwentyOne backend.
        machine_auth (two1.server.machine_auth_wallet.MachineAuthWallet): a wallet
            used for machine authentication.
        resource (str): a URI of the form scheme://host:port/path with `http`
            and `https` strictly enforced as required schemes.
        info_only (bool): if True, do not purchase the resource, and cause the
            function to write only the 402-related headers.
        payment_method (str): the payment method used for the purchase.
        header (tuple): list of HTTP headers to send with the request.
        method (str): the HTTP method/verb to make with the request.
        output_file (str): name of the file to redirect function output.
        data (str): serialized data to send with the request. The function will
            attempt to deserialize the data and determine its encoding type.
        data_file (str): name of the data file to send in HTTP body.
        maxprice (int): allowed maximum price (in satoshis) of the resource.
        mock_requests (bool): skip 402 request and return an empty 200 response,
            intended for developer testing.

    Raises:
        click.ClickException: if some set of parameters or behavior cause the
            purchase to not complete successfully for any reason.
    """
    # Find the correct payment method
    if payment_method == 'offchain':
        requests = bitrequests.BitTransferRequests(machine_auth,
                                                   config.username, client)
    elif payment_method == 'onchain':
        requests = bitrequests.OnChainRequests(machine_auth.wallet)
    elif payment_method == 'channel':
        requests = bitrequests.ChannelRequests(machine_auth.wallet)
    else:
        raise click.ClickException(
            uxstring.UxString.buy_bad_payment_method.format(payment_method))

    # Request user consent if they're creating a channel for the first time
    if payment_method == 'channel' and not requests._channelclient.list():
        confirmed = click.confirm(uxstring.UxString.buy_channel_warning.format(
            requests.DEFAULT_DEPOSIT_AMOUNT, statemachine.
            PaymentChannelStateMachine.PAYMENT_TX_MIN_OUTPUT_AMOUNT),
                                  default=True)
        if not confirmed:
            raise click.ClickException(uxstring.UxString.buy_channel_aborted)

    resource = parse_resource(resource)

    # Retrieve 402-related header information, print it, then exit
    if info_only:
        response = requests.get_402_info(resource)
        return logger.info('\n'.join(
            ['{}: {}'.format(key, val) for key, val in response.items()]))

    # Collect HTTP header parameters into a single dictionary
    headers = {
        key.strip(): value.strip()
        for key, value in (h.split(':') for h in header)
    }

    # Handle data if applicable
    if data or data_file:
        method = 'POST' if method == 'GET' else method
    if data:
        data, headers['Content-Type'] = _parse_post_data(data)

    # Make the paid request for the resource
    try:
        kwargs = {'max_price': maxprice, 'data': data, 'headers': headers}
        if data_file:
            kwargs['files'] = {'file': data_file}
        response = requests.request(method.lower(),
                                    resource,
                                    mock_requests=mock_requests,
                                    **kwargs)
    except bitrequests.ResourcePriceGreaterThanMaxPriceError as e:
        raise click.ClickException(
            uxstring.UxString.Error.resource_price_greater_than_max_price.
            format(e))
    except wallet_exceptions.DustLimitError as e:
        raise click.ClickException(e)
    except bitrequests.InsufficientBalanceError as e:
        raise click.ClickException(e)
    except RequestException as e:
        raise exceptions.Two1Error('Requests exception: %s' % e)

    # Write response text to stdout or a filename if provided
    if not output_file:
        try:
            json_resp = response.json()
        except ValueError:
            logger.info(response.content, nl=False)
        else:
            if isinstance(json_resp, dict):
                ordered = OrderedDict(sorted(json_resp.items()))
                logger.info(json.dumps(ordered, indent=4), nl=False)
            else:
                logger.info(json.dumps(json_resp, indent=4), nl=False)
    else:
        with open(output_file, 'wb') as f:
            logger.info(response.content, file=f, nl=False)

    logger.info('', err=True)  # newline for pretty-printing errors to stdout

    # We will have paid iff response is a paid_response (regardless of
    # response.ok)
    if hasattr(response, 'amount_paid'):
        # Fetch and write out diagnostic payment information for balances
        if payment_method == 'offchain':
            twentyone_balance = client.get_earnings()["total_earnings"]
            logger.info(uxstring.UxString.buy_balances.format(
                response.amount_paid, '21.co', twentyone_balance),
                        err=True)
        elif payment_method == 'onchain':
            onchain_balance = min(requests.wallet.confirmed_balance(),
                                  requests.wallet.unconfirmed_balance())
            logger.info(uxstring.UxString.buy_balances.format(
                response.amount_paid, 'blockchain', onchain_balance),
                        err=True)
        elif payment_method == 'channel':
            channel_client = requests._channelclient
            channel_client.sync()
            channels_balance = sum(
                s.balance for s in (channel_client.status(url)
                                    for url in channel_client.list())
                if s.state == channels.PaymentChannelState.READY)
            logger.info(uxstring.UxString.buy_balances.format(
                response.amount_paid, 'payment channels', channels_balance),
                        err=True)

    if not response.ok:
        sys.exit(1)
コード例 #17
0
ファイル: nginx.py プロジェクト: BlueSpaceCookie/blockchain
def create_config(dirname):
    """Create a nginx location file that redirects
    all requests with the prefix of the appname to the
    correct socket & process belonging to that app.

    i.e. curl 0.0.0.0/myapp1 should redirect requests
    to unix:/mysocketpath.sock @ the route /

    This allows for multiple apps to be namespaced and
    hosted on a single machine.

    Args:
        dirname (string): directory the app is located in.

    Returns:
        bool: True if the process was successfully completed, False otherwise.
    """
    plat = detect_os()
    rv = False
    appdir = dir_to_absolute(dirname)
    appname = absolute_path_to_foldername(appdir)
    with tempfile.NamedTemporaryFile() as tf:
        nginx_site_includes_file = """location /%s {
        rewrite ^/%s(.*) /$1 break;
        proxy_pass http://unix:%s%s.sock;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
}""" % (appname, appname, appdir, appname)
        tf.write(nginx_site_includes_file.encode())
        tf.flush()
        try:
            subprocess.check_output([
                "sudo", "cp", tf.name,
                "{}/etc/nginx/sites-available/{}".format(
                    "/usr/local" if "darwin" in plat else "", appname)
            ])
            subprocess.check_output([
                "sudo", "chmod", "644",
                "{}/etc/nginx/sites-available/{}".format(
                    "/usr/local" if "darwin" in plat else "", appname)
            ])
            subprocess.check_output([
                "sudo", "rm", "-f", "{}/etc/nginx/site-includes/{}".format(
                    "/usr/local" if "darwin" in plat else "", appname)
            ])
            subprocess.check_output([
                "sudo", "ln", "-s", "{}/etc/nginx/sites-available/{}".format(
                    "/usr/local" if "darwin" in plat else "", appname),
                "{}/etc/nginx/site-includes/{}".format(
                    "/usr/local" if "darwin" in plat else "", appname)
            ])
            if "darwin" in plat:
                if os.path.exists("/usr/local/var/run/nginx.pid"):
                    subprocess.check_output("sudo nginx -s stop", shell=True)
                subprocess.check_output("sudo nginx", shell=True)
            else:
                subprocess.check_output(
                    ["sudo", "service", "nginx", "restart"])
            rv = True
        except subprocess.CalledProcessError as e:
            raise exceptions.Two1Error(
                uxstring.UxString.failed_configuring_nginx.format(e))
    return rv