Ctrl K
ComunidadGuías…

examples/http_signature.v

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// vtest build: !(openbsd && gcc) && !(sanitize-memory-clang || docker-ubuntu-musl)
// HTTP Message Signatures example: signs an outbound request with
// Ed25519 (using the RFC 9421 §B.1.4 test key in PEM form) and then
// verifies the result with the matching public key.
//
// Run with:  v run examples/http_signature.v
import net.http
import net.http.signature

const ed25519_private_pem = '-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIJ+DYvh6SEqVTm50DFtMDoQikTmiCqirVv9mWG9qfSnF
-----END PRIVATE KEY-----'

const ed25519_public_pem = '-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAJrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=
-----END PUBLIC KEY-----'

fn main() {
	demo_sign_and_verify_request()!
	demo_two_signatures()!
}

// demo_sign_and_verify_request walks through the common path: the
// client signs a request before sending; the server verifies before
// processing.
fn demo_sign_and_verify_request() ! {
	priv := signature.Key.from_pem(ed25519_private_pem)!.with_keyid('test-key-ed25519')
	pub_key := signature.Key.from_pem(ed25519_public_pem)!

	mut req := http.Request{
		method: .post
		url:    'https://example.com/foo'
	}
	req.header.add_custom('Host', 'example.com')!
	req.header.add_custom('Date', 'Tue, 20 Apr 2021 02:07:55 GMT')!
	req.header.add_custom('Content-Type', 'application/json')!
	req.header.add_custom('Content-Length', '18')!

	signature.sign_request(mut req, priv,
		components: ['date', '@method', '@path', '@authority', 'content-type', 'content-length']
		created:    1618884473
		label:      'sig-b26'
	)!

	si := req.header.get_custom('Signature-Input') or { '' }
	sig := req.header.get_custom('Signature') or { '' }
	println('Signature-Input: ${si}')
	println('Signature:       ${sig}')

	signature.verify_request(req, pub_key,
		required_components: ['date', '@method', '@path', '@authority', 'content-type', 'content-length']
	)!
	println('  ✓ verified with the matching public key')
}

// demo_two_signatures shows a TLS-terminating proxy scenario: the
// client signs the original request, the proxy adds its own signature
// over the same message under a different label, and the backend
// verifies both independently.
fn demo_two_signatures() ! {
	client_key := signature.Key.hmac_sha256('client-shared-secret'.bytes())!.with_keyid('client')
	proxy_key := signature.Key.hmac_sha256('proxy-shared-secret'.bytes())!.with_keyid('proxy')

	mut req := http.Request{
		method: .get
		url:    'https://api.example.com/orders/42'
	}
	req.header.add_custom('Host', 'api.example.com')!
	req.header.add_custom('Date', 'Tue, 20 Apr 2021 02:07:55 GMT')!

	// `created` defaults to `time.now().unix()` when not set —
	// fine for a real client. Pinned here so the example output
	// is reproducible across runs.
	signature.sign_request(mut req, client_key,
		components: ['@method', '@target-uri', 'date']
		label:      'client-sig'
		created:    1618884473
	)!
	signature.sign_request(mut req, proxy_key,
		components: ['@method', '@authority', 'date']
		label:      'proxy-sig'
		created:    1618884480
	)!

	si := req.header.get_custom('Signature-Input') or { '' }
	println('\nMerged Signature-Input: ${si}')

	signature.verify_request(req, client_key,
		label:               'client-sig'
		required_components: ['@method', '@target-uri', 'date']
	)!
	signature.verify_request(req, proxy_key,
		label:               'proxy-sig'
		required_components: ['@method', '@authority', 'date']
	)!
	println('  ✓ both labelled signatures verified')
}