@derhuerst/gemini

    1.2.1 • Public • Published

    gemini

    Gemini protocol server & client.

    npm version build status ISC-licensed minimum Node.js version support me via GitHub Sponsors chat with me on Twitter

    Installation

    npm install @derhuerst/gemini

    Usage

    Server

    The following code assumes that you have a valid SSL certificate & key.

    const {createServer, DEFAULT_PORT} = require('@derhuerst/gemini')
    
    const handleRequest = (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()
    	}
    }
    
    const server = createServer({
    	cert: , // certificate (+ chain)
    	key: , // private key
    	passphrase: , // passphrase, if the key is encrypted
    }, handleRequest)
    
    server.listen(DEFAULT_PORT)
    server.on('error', console.error)

    Client

    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-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, section 1.4.3

    This library leaves it up to you how to ask the user for approval. As an example, we're going to build a simple CLI prompt:

    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

    createServer

    const createServer = require('@derhuerst/gemini/server')
    createServer(opt = {}, onRequest)

    opt extends the following defaults:

    {
    	// SSL certificate & key
    	cert: null, key: null, passphrase: null,
    	// additional options to be passed into `tls.createServer`
    	tlsOpt: {},
    	// verify the ALPN ID requested by the client
    	// see https://de.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation
    	verifyAlpnId: alpnId => alpnId ? alpnId === ALPN_ID : true,
    }

    request

    const request = require('@derhuerst/gemini/client')
    request(pathOrUrl, opt = {}, cb)

    opt extends the following defaults:

    {
    	// follow redirects automatically
    	// Can also be a function `(nrOfRedirects, response) => boolean`.
    	followRedirects: false,
    	// client certificates
    	useClientCerts: false,
    	letUserConfirmClientCertUsage: null,
    	clientCertStore: defaultClientCertStore,
    	// time to wait for socket connection & TLS handshake
    	connectTimeout: 60 * 1000, // 60s
    	// additional options to be passed into `tls.connect`
    	tlsOpt: {},
    	// verify the ALPN ID chosen by the server
    	// see https://de.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation
    	verifyAlpnId: alpnId => alpnId ? (alpnId === ALPN_ID) : true,
    }

    connect

    const connect = require('@derhuerst/gemini/connect')
    connect(opt = {}, cb)

    opt extends the following defaults:

    {
    	hostname: '127.0.0.1',
    	port: 1965,
    	// client certificate
    	cert: null, key: null, passphrase: null,
    	// time to wait for socket connection & TLS handshake
    	connectTimeout: 60 * 1000, // 60s
    	// additional options to be passed into `tls.connect`
    	tlsOpt: {},
    }

    Related

    • gemini-fetch – Load data from the Gemini protocol the way you would fetch from HTTP in JavaScript
    • dioscuri – A gemtext (text/gemini) parser with support for streaming, ASTs, and CSTs

    Contributing

    If you have a question or need support using gemini, please double-check your code and setup first. If you think you have found a bug or want to propose a feature, use the issues page.

    Install

    npm i @derhuerst/gemini

    DownloadsWeekly Downloads

    11

    Version

    1.2.1

    License

    ISC

    Unpacked Size

    33 kB

    Total Files

    15

    Last publish

    Collaborators

    • derhuerst