summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--connect.js1
-rw-r--r--examples/server.js2
-rw-r--r--lib/request-parser.js1
-rw-r--r--lib/response-parser.js14
-rw-r--r--readme.md139
-rw-r--r--server.js3
6 files changed, 149 insertions, 11 deletions
diff --git a/connect.js b/connect.js
index bca3d20..d2e8a6e 100644
--- a/connect.js
+++ b/connect.js
@@ -22,7 +22,6 @@ const connectToGeminiServer = (opt, cb) => {
port: DEFAULT_PORT,
cert: null, key: null, passphrase: null,
tlsOpt: {},
- // todo: TOFU via isTrustedCertificate()
...opt,
}
diff --git a/examples/server.js b/examples/server.js
index d9eb587..5a9779e 100644
--- a/examples/server.js
+++ b/examples/server.js
@@ -34,7 +34,7 @@ createCert('example.org')
tlsOpt: keys,
// todo: SNICallback
}, onRequest)
- server.on('error', onError)
+ server.on('error', console.error)
server.listen(DEFAULT_PORT, (err) => {
if (err) return onError(err)
diff --git a/lib/request-parser.js b/lib/request-parser.js
index 04c5cd6..6cfba3d 100644
--- a/lib/request-parser.js
+++ b/lib/request-parser.js
@@ -1,7 +1,6 @@
'use strict'
const {Transform} = require('stream')
-const {MESSAGES} = require('./statuses')
// https://gemini.circumlunar.space/docs/spec-spec.txt, 1.2
// > Gemini requests are a single CRLF-terminated line with the
diff --git a/lib/response-parser.js b/lib/response-parser.js
index cb50f0a..2d64a47 100644
--- a/lib/response-parser.js
+++ b/lib/response-parser.js
@@ -79,12 +79,12 @@ const createResponseParser = () => {
return out
}
-const p = createResponseParser()
-p.on('error', console.error)
-p.on('header', h => console.log('header', h))
-p.on('data', d => console.log('data', d.toString('utf8')))
-const b = str => Buffer.from(str, 'utf8')
-p.write(b('31 gemini://examp'))
-p.write(b('le.org/foo?bar\r\n'))
+// const p = createResponseParser()
+// p.on('error', console.error)
+// p.on('header', h => console.log('header', h))
+// p.on('data', d => console.log('data', d.toString('utf8')))
+// const b = str => Buffer.from(str, 'utf8')
+// p.write(b('31 gemini://examp'))
+// p.write(b('le.org/foo?bar\r\n'))
module.exports = createResponseParser
diff --git a/readme.md b/readme.md
index 2e3118f..4a515e5 100644
--- a/readme.md
+++ b/readme.md
@@ -19,8 +19,145 @@ npm install @derhuerst/gemini
## Usage
+### Server
+
+The following code assumes that you have a valid SSL certificate & key.
+
+```js
+const {createServer, DEFAULT_PORT} = require('@derhuerst/gemini')
+
+const onError = (err) => {
+ console.error(err)
+ process.exit(1)
+}
+
+const server = createGeminiServer({
+ cert: …, // certificate (+ chain)
+ key: …, // private key
+ passphrase: …, // passphrase, if the key is encrypted
+}, (req, res) => {
+ if (req.path === '/foo') {
+ if (!req.clientFingerprint) {
+ return res.requestTransientClientCert('/foo is secret!')
+ }
+ res.write('foo')
+ res.end('!')
+ } else if (req.path === '/bar') {
+ res.redirect('/foo')
+ } else {
+ res.gone()
+ }
+})
+
+server.listen(DEFAULT_PORT)
+server.on('error', console.error)
+```
+
+### Client
+
+```js
+const request = require('@derhuerst/gemini/client')
+
+request('/bar', (err, res) => {
+ if (err) {
+ console.error(err)
+ process.exit(1)
+ }
+
+ console.log(res.statusCode, res.statusMessage)
+ if (res.meta) console.log(res.meta)
+ res.pipe(process.stdout)
+})
+```
+
+#### [TOFU](https://en.wikipedia.org/wiki/Trust_on_first_use)-style client certificates
+
+> Interactive clients for human users MUST inform users that such a session has been requested and require the user to approve generation of such a certificate. Transient certificates MUST NOT be generated automatically.
+– [Gemini spec](https://gemini.circumlunar.space/docs/spec-spec.txt), section 1.4.3
+
+If is up to you how to implement that approval process. As an example, we're going to build a simple CLI prompt:
+
+```js
+const {createInterface} = require('readline')
+
+const letUserConfirmClientCertUsage = ({host, reason}, cb) => {
+ const prompt = createInterface({
+ input: process.stdin,
+ output: process.stdout,
+ history: 0,
+ })
+ prompt.question(`Send client cert to ${host}? Server says: "${reason}". y/n > `, (confirmed) => {
+ prompt.close()
+ cb(confirmed === 'y' || confirmed === 'Y')
+ })
+}
+
+request('/foo', {
+ // opt into client certificates
+ useClientCerts: true,
+ letUserConfirmClientCertUsage,
+}, cb)
+```
+
+
+## API
+
+```js
+const createServer = require('@derhuerst/gemini/server')
+createServer(opt = {}, onRequest)
+```
+
+`opt` extends the following defaults:
+
+```js
+{
+ // SSL certificate & key
+ cert: null, key: null, passphrase: null,
+ // additional options to be passed into `tls.createServer`
+ tlsOpt: {},
+}
+```
+
+---
+
+```js
+const request = require('@derhuerst/gemini/client')
+request(pathOrUrl, opt = {}, cb)
+```
+
+`opt` extends the following defaults:
+
+```js
+{
+ // follow redirects automatically
+ followRedirects: false,
+ // client certificates
+ useClientCerts: false,
+ letUserConfirmClientCertUsage: null,
+ clientCertStore: defaultClientCertStore,
+ // additional options to be passed into `tls.connect`
+ tlsOpt: {},
+}
+```
+
+---
+
+```js
+const connect = require('@derhuerst/gemini/connect')
+connect(opt = {}, cb)
+```
+
+`opt` extends the following defaults:
+
```js
-todo
+{
+ hostname: '127.0.0.1',
+ port: 1965,
+ // client certificate
+ cert: null, key: null, passphrase: null,
+ // additional options to be passed into `tls.connect`
+ tlsOpt: {},
+}
```
diff --git a/server.js b/server.js
index cef2c4c..aa7afb7 100644
--- a/server.js
+++ b/server.js
@@ -15,8 +15,10 @@ const createGeminiServer = (opt = {}, onRequest) => {
opt = {}
}
const {
+ cert, key, passphrase,
tlsOpt,
} = {
+ cert: null, key: null, passphrase: null,
tlsOpt: {},
...opt,
}
@@ -103,6 +105,7 @@ const createGeminiServer = (opt = {}, onRequest) => {
// the request with a "transient certificate" to initiate a client
// > certificate section.
rejectUnauthorized: false,
+ cert, key, passphrase,
...tlsOpt,
}, onConnection)