Esempio n. 1
0
async def api_lnurlscan(code: str):
    try:
        url = lnurl.Lnurl(code)
    except ValueError:
        return jsonify({"message": "invalid lnurl"}), HTTPStatus.BAD_REQUEST

    domain = urlparse(url.url).netloc

    # params is what will be returned to the client
    params: Dict = {"domain": domain}

    if url.is_login:
        params.update(kind="auth")
        params.update(callback=url.url)  # with k1 already in it

        lnurlauth_key = g.wallet.lnurlauth_key(domain)
        params.update(
            pubkey=lnurlauth_key.verifying_key.to_string("compressed").hex())
    else:
        async with httpx.AsyncClient() as client:
            r = await client.get(url.url, timeout=40)
            if r.is_error:
                return (
                    jsonify({
                        "domain": domain,
                        "message": "failed to get parameters"
                    }),
                    HTTPStatus.SERVICE_UNAVAILABLE,
                )

        try:
            jdata = json.loads(r.text)
            data: lnurl.LnurlResponseModel = lnurl.LnurlResponse.from_dict(
                jdata)
        except (json.decoder.JSONDecodeError,
                lnurl.exceptions.LnurlResponseException):
            return (
                jsonify({
                    "domain": domain,
                    "message": f"got invalid response '{r.text[:200]}'",
                }),
                HTTPStatus.SERVICE_UNAVAILABLE,
            )

        if type(data) is lnurl.LnurlChannelResponse:
            return (
                jsonify({
                    "domain": domain,
                    "kind": "channel",
                    "message": "unsupported"
                }),
                HTTPStatus.BAD_REQUEST,
            )

        params.update(**data.dict())

        if type(data) is lnurl.LnurlWithdrawResponse:
            params.update(kind="withdraw")
            params.update(fixed=data.min_withdrawable == data.max_withdrawable)

            # callback with k1 already in it
            parsed_callback: ParseResult = urlparse(data.callback)
            qs: Dict = parse_qs(parsed_callback.query)
            qs["k1"] = data.k1

            # balanceCheck/balanceNotify
            if "balanceCheck" in jdata:
                params.update(balanceCheck=jdata["balanceCheck"])

            # format callback url and send to client
            parsed_callback = parsed_callback._replace(
                query=urlencode(qs, doseq=True))
            params.update(callback=urlunparse(parsed_callback))

        if type(data) is lnurl.LnurlPayResponse:
            params.update(kind="pay")
            params.update(fixed=data.min_sendable == data.max_sendable)
            params.update(description_hash=data.metadata.h)
            params.update(description=data.metadata.text)
            if data.metadata.images:
                image = min(data.metadata.images,
                            key=lambda image: len(image[1]))
                data_uri = "data:" + image[0] + "," + image[1]
                params.update(image=data_uri)
            params.update(commentAllowed=jdata.get("commentAllowed", 0))

    return jsonify(params)
Esempio n. 2
0
async def api_lnurlscan(code: str):
    try:
        url = lnurl.Lnurl(code)
    except ValueError:
        return jsonify({"error": "invalid lnurl"}), HTTPStatus.BAD_REQUEST

    domain = urlparse(url.url).netloc
    if url.is_login:
        return jsonify({
            "domain": domain,
            "kind": "auth",
            "error": "unsupported"
        }), HTTPStatus.BAD_REQUEST

    async with httpx.AsyncClient() as client:
        r = await client.get(url.url, timeout=40)
        if r.is_error:
            return jsonify({
                "domain": domain,
                "error": "failed to get parameters"
            }), HTTPStatus.SERVICE_UNAVAILABLE

    try:
        jdata = json.loads(r.text)
        data: lnurl.LnurlResponseModel = lnurl.LnurlResponse.from_dict(jdata)
    except (json.decoder.JSONDecodeError,
            lnurl.exceptions.LnurlResponseException):
        return (
            jsonify({
                "domain": domain,
                "error": f"got invalid response '{r.text[:200]}'"
            }),
            HTTPStatus.SERVICE_UNAVAILABLE,
        )

    if type(data) is lnurl.LnurlChannelResponse:
        return jsonify({
            "domain": domain,
            "kind": "channel",
            "error": "unsupported"
        }), HTTPStatus.BAD_REQUEST

    params: Dict = data.dict()
    if type(data) is lnurl.LnurlWithdrawResponse:
        params.update(kind="withdraw")
        params.update(fixed=data.min_withdrawable == data.max_withdrawable)

        # callback with k1 already in it
        parsed_callback: ParseResult = urlparse(data.callback)
        qs: Dict = parse_qs(parsed_callback.query)
        qs["k1"] = data.k1
        parsed_callback = parsed_callback._replace(
            query=urlencode(qs, doseq=True))
        params.update(callback=urlunparse(parsed_callback))

    if type(data) is lnurl.LnurlPayResponse:
        params.update(kind="pay")
        params.update(fixed=data.min_sendable == data.max_sendable)
        params.update(description_hash=data.metadata.h)
        params.update(description=data.metadata.text)
        if data.metadata.images:
            image = min(data.metadata.images, key=lambda image: len(image[1]))
            data_uri = "data:" + image[0] + "," + image[1]
            params.update(image=data_uri)
        params.update(commentAllowed=jdata.get("commentAllowed", 0))

    params.update(domain=domain)
    return jsonify(params)