This repository has been archived by the owner on Sep 21, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 40
/
server.ts
136 lines (120 loc) · 4.5 KB
/
server.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/**
* To run the file, it requires two environment variables to be set.
* `PROVIDER_URL` is a JSON RPC endpoint. Infura works just fine. For Rinkeby test network,
* you could set it to `PROVIDER_URL="https://rinkeby.infura.io/"`. Another variable is `MNEMONIC`.
* It is a [12-word seed phrase](https://github.com/pirapira/ethereum-word-list/blob/master/README.md#mnemonic-phrase).
* For example, `MNEMONIC="brain surround have swap horror body response double fire dumb bring hazard"`
*
* Start this file then:
*
* yarn build
* PROVIDER_URL="https://rinkeby.infura.io/" MNEMONIC="brain surround have swap horror body response double fire dumb bring hazard" node server.js
*
* The script runs 3 core endpoints:
* `http://localhost:3000/content` provides an example of the paid content.
* `http://localhost:3001/accept` accepts payment.
* `http://localhost:3001/verify/:token` verifies token that `/accept` generates.
*
* The client side for buying the content is provided in `client.ts` file.
*/
import * as express from 'express'
import * as Web3 from 'web3'
import Machinomy from 'machinomy'
import * as bodyParser from 'body-parser'
import { AcceptTokenRequestSerde } from 'machinomy/lib/accept_token_request'
import { PaymentChannelSerde } from 'machinomy/lib/PaymentChannel'
import fetcher from 'machinomy/lib/util/fetcher'
import HDWalletProvider from '@machinomy/hdwallet-provider'
async function main () {
const PROVIDER_URL = String(process.env.PROVIDER_URL)
const MNEMONIC = String(process.env.MNEMONIC)
const HOST = 'localhost'
const APP_PORT = 3000
const HUB_PORT = 3001
const provider = HDWalletProvider.http(MNEMONIC, PROVIDER_URL)
const web3 = new Web3(provider)
/**
* Account that receives payments.
*/
let receiver = await provider.getAddress(0)
/**
* Create machinomy instance that provides API for accepting payments.
*/
let machinomy = new Machinomy(receiver, web3, { databaseUrl: 'nedb://./server' })
let hub = express()
hub.use(bodyParser.json())
hub.use(bodyParser.urlencoded({ extended: false }))
/**
* Recieve an off-chain payment issued by `machinomy buy` command.
*/
hub.post('/accept', async (req, res) => {
const body = await machinomy.acceptPayment(req.body)
res.status(202).header('Paywall-Token', body.token).send(body)
})
/**
* Verify the token that `/accept` generates.
*/
hub.get('/verify/:token', async (req, res) => {
const token = req.params.token as string
const acceptTokenRequest = AcceptTokenRequestSerde.instance.deserialize({ token })
const isAccepted = (await machinomy.acceptToken(acceptTokenRequest)).status
if (isAccepted) {
res.status(200).send({ status: 'ok' })
} else {
res.status(400).send({ status: 'token is invalid' })
}
})
hub.get('/channels', async (req, res) => {
const channels = await machinomy.channels()
res.status(200).send(channels.map(PaymentChannelSerde.instance.serialize))
})
hub.get('/claim/:channelid', async (req, res) => {
try {
let channelId = req.params.channelid
await machinomy.close(channelId)
res.status(200).send('Claimed')
} catch (error) {
res.status(404).send('No channel found')
console.error(error)
}
})
hub.listen(HUB_PORT, () => {
console.log('HUB is ready on port ' + HUB_PORT)
})
let app = express()
let paywallHeaders = () => {
let headers: { [index: string]: string } = {}
headers['Paywall-Version'] = '0.0.3'
headers['Paywall-Price'] = '1000'
headers['Paywall-Address'] = receiver
headers['Paywall-Gateway'] = `http://${HOST}:${HUB_PORT}/accept`
return headers
}
/**
* Example of serving a paid content. You can buy it with `machinomy buy http://localhost:3000/content` command.
*/
app.get('/content', async (req, res) => {
let reqUrl = `http://${HOST}:${HUB_PORT}/verify`
let content = req.get('authorization')
if (content) {
let token = content.split(' ')[1]
let response = await fetcher.fetch(reqUrl + '/' + token)
let json = await response.json()
let status = json.status
if (status === 'ok') {
res.send('Thank you for your purchase!')
} else {
res.status(402).set(paywallHeaders()).send('Content is not available')
}
} else {
res.status(402).set(paywallHeaders()).send('Content is not available')
}
})
app.listen(APP_PORT, function () {
console.log('Content proveder is ready on ' + APP_PORT)
})
}
main().catch(error => {
console.error(error)
process.exit(1)
})