• Stars
    star
    148
  • Rank 249,983 (Top 5 %)
  • Language
    Go
  • License
    Mozilla Public Li...
  • Created over 6 years ago
  • Updated almost 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Go middleware for monetizing your API on a per-request basis with Bitcoin and Lightning ⚡️

ln-paywall

GoDoc Build Status Go Report Card GitHub Releases

Go middleware for monetizing your API on a per-request basis with Bitcoin and Lightning ⚡️

Middlewares for:

A client package exists as well to make consuming LN-paywalled APIs extremely easy (you just use it like the standard Go http.Client and the payment handling is done in the background).

An API gateway is on the roadmap as well, which you can use to monetize your API that's written in any language, not just in Go.

Contents

Purpose

Until the rise of cryptocurrencies, if you wanted to monetize your API (set up a paywall), you had to:

  1. Use a centralized service (like PayPal)
    • Can shut you down any time
    • High fees
    • Your API users need an account
    • Can be hacked
  2. Keep track of your API users (keep accounts and their API keys in some database)
    • Privacy concerns
    • Data breaches / leaks
  3. Charge for a bunch of requests, like 10.000 at a time, because real per-request payments weren't possible

With cryptocurrencies in general some of those problems were solved, but with long confirmation times and high per-transaction fees a real per-request billing was still not feasable.

But then came the Lightning Network, an implementation of routed payment channels, which enables real near-instant microtransactions with extremely low fees, which cryptocurrencies have long promised, but never delivered. It's a second layer on top of existing cryptocurrencies like Bitcoin that scales far beyond the limitations of the underlying blockchain.

ln-paywall makes it easy to set up an API paywall for payments over the Lightning Network.

How it works

With ln-paywall you can simply use one of the provided middlewares in your Go web service to have your web service do two things:

  1. The first request gets rejected with the 402 Payment Required HTTP status, a Content-Type: application/vnd.lightning.bolt11 header and a Lightning (BOLT-11-conforming) invoice in the body
  2. The second request must contain a X-Preimage header with the preimage of the paid Lightning invoice (hex encoded). The middleware checks if 1) the invoice was paid and 2) not already used for a previous request. If both preconditions are met, it continues to the next middleware or final request handler.

Prerequisites

There are currently two prerequisites:

  1. A running Lightning Network node. The middleware connects to the node for example to create invoices for a request. The ln package currently provides factory functions for the following LN implementations:
    • lnd
      • Requires the node to listen to gRPC connections
      • If you don't run it locally, it needs to listen to connections from external machines (so for example on 0.0.0.0 instead of localhost) and has the TLS certificate configured to include the external IP address of the node.
    • c-lightning with Lightning Charge
      • Run for example with Docker: docker run -d -u `id -u` -v `pwd`/data:/data -p 9112:9112 -e API_TOKEN=secret shesek/lightning-charge
      • Vanilla c-lightning (without Lightning Charge) won't be supported as long as c-lightning's RPC API only works via Unix socket and cannot be used as a remote server, because this is not a good fit for potentially multiple web service instances elastically scaled across a cluster of host machines
    • eclair (not implemented yet - PRs Welcome )
    • Roll your own!
      • Just implement the simple wall.LNClient interface (only two methods!)
  2. A supported storage mechanism. It's used to cache preimages that have been used as a payment for an API call, so that a user can't do multiple requests with the same preimage of a settled Lightning payment. The wall package currently provides factory functions for the following storages:
    • A simple Go map
      • The fastest option, but 1) can't be used across horizontally scaled service instances and 2) doesn't persist data, so when you restart your server, users can re-use old preimages
    • bbolt - a fork of Bolt maintained by CoreOS
      • Very fast, doesn't require any remote or local TCP connections and persists the data, but can't be used across horizontally scaled service instances because it's file-based. Production-ready for single-instance web services though.
    • Redis
      • Although the slowest of these options, still fast and most suited for popular web services: Requires a remote or local TCP connection and some administration, but allows data persistency and can even be used with a horizontally scaled web service
      • Run for example with Docker: docker run -d -p 6379:6379 redis
        • Note: In production you should use a configuration with password (check out bitnami/redis which makes that easy)!
    • groupcache (not implemented yet - PRs Welcome )
    • Roll your own!
      • Just implement the simple wall.StorageClient interface (only two methods!)

Usage

GoDoc

Get the package with go get -u github.com/philippgille/ln-paywall/....

We strongly encourage you to use vendoring, because as long as ln-paywall is version 0.x, breaking changes may be introduced in new versions, including changes to the package name / import path. The project adheres to Semantic Versioning and all notable changes to this project are documented in RELEASES.md.

Middleware

The best way to see how to use ln-paywall is by example. In the below examples we create a web service that responds to requests to /ping with "pong", using Gin as the web framework.

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/philippgille/ln-paywall/ln"
	"github.com/philippgille/ln-paywall/storage"
	"github.com/philippgille/ln-paywall/wall"
)

func main() {
	r := gin.Default()

	// Configure middleware
	invoiceOptions := wall.DefaultInvoiceOptions // Price: 1 Satoshi; Memo: "API call"
	lndOptions := ln.DefaultLNDoptions           // Address: "localhost:10009", CertFile: "tls.cert", MacaroonFile: "invoice.macaroon"
	storageClient := storage.NewGoMap()          // Local in-memory cache
	lnClient, err := ln.NewLNDclient(lndOptions)
	if err != nil {
		panic(err)
	}
	// Use middleware
	r.Use(wall.NewGinMiddleware(invoiceOptions, lnClient, storageClient))

	r.GET("/ping", func(c *gin.Context) {
		c.String(http.StatusOK, "pong")
	})

	r.Run() // Listen and serve on 0.0.0.0:8080
}

This is just the most basic example. See the list of examples below for examples with other web frameworks / routers / just the stdlib, as well as for a more complex and useful example.

List of examples

Follow the links to the example code files.

Simple examples to show the use for the different web frameworks / routers / just the stdlib:

More complex and useful example:

Client

package main

import (
	"fmt"
	"io/ioutil"

	"github.com/philippgille/ln-paywall/ln"
	"github.com/philippgille/ln-paywall/pay"
)

func main() {
	// Set up client
	lndOptions := ln.LNDoptions{ // Default address: "localhost:10009", CertFile: "tls.cert"
		MacaroonFile: "admin.macaroon", // admin.macaroon is required for making payments
	}
	lnClient, err := ln.NewLNDclient(lndOptions)
	if err != nil {
		panic(err)
	}
	client := pay.NewClient(nil, lnClient) // Uses http.DefaultClient if no http.Client is passed

	// Send request to an ln-paywalled API
	res, err := client.Get("http://localhost:8080/ping")
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	// Print response body
	resBody, err := ioutil.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(resBody))
}

You can also view this example here.

Related Projects

More Repositories

1

gokv

Simple key-value store abstraction and implementations for Go (Redis, Consul, etcd, bbolt, BadgerDB, LevelDB, Memcached, DynamoDB, S3, PostgreSQL, MongoDB, CockroachDB and many more)
Go
736
star
2

chromem-go

Embeddable vector database for Go with Chroma-like interface and zero third-party dependencies. In-memory with optional persistence.
Go
234
star
3

serve

serve starts a simple temporary static file server in your current directory and prints your IP address to share with colleagues
Go
153
star
4

libra-sdk-go

Go SDK for the Libra cryptocurrency
Go
21
star
5

lightning.ws

Web services and website files for https://lightning.ws
HTML
12
star
6

hello-netcoreapp

Basic .NET Core console application with additional scripts and files for building the app and creating release artifacts for a framework-dependent deployment, self-contained deployment, Docker image, Chocolatey package and AppImage
Shell
6
star
7

gobin-info

Lists your locally installed Go binaries alongside their version and original Git repo
Go
2
star
8

go-wasm

Examples of how to work with WebAssembly and WASI in Go
Go
2
star
9

apiomat-cli

aom - CLI for ApiOmat, written in Go
Go
1
star
10

scoop-bucket

Scoop bucket for my apps
1
star
11

alexa-blockchain-explorer

Alexa skill for Blockchain data and info
Java
1
star
12

hello-nancy

Hello World project for the Nancy framework
C#
1
star
13

apiomat-sdk-go

Go (golang) SDK for ApiOmat
Go
1
star
14

ln-paywalled-bitcoin-vanity-address-generator-api

The name says it all: An API for generating Bitcoin vanity addresses, with a paywall for paying via Lightning Network
1
star