mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-08-22 07:16:03 +00:00
Four hand-rolled base64url implementations existed: Base64URLCoding in the Nostr folder, private duplicates in NostrEmbeddedBitChat and CashuTokenDecoder, and an inline chain in VerificationService. Padding handling differed per call site, which is exactly the drift #642 warns about. Move Base64URLCoding into BitFoundation (the shared-components package), make it public, and route all call sites through it. The unified decode keeps CashuTokenDecoder's padding normalization - strip any '=' then re-pad - because external wallets emit both padded and unpadded forms; it accepts a superset of what the old Nostr-side decode accepted and returns identical results for every input the old decoder handled. Encoding is byte-for-byte identical to all three prior copies. Adds unit tests covering alphabet substitution, padded/unpadded forms, every padding length, and malformed-input rejection. Fixes #642
63 lines
2.2 KiB
Swift
63 lines
2.2 KiB
Swift
//
|
|
// Base64URLCodingTests.swift
|
|
// bitchatTests
|
|
//
|
|
// This is free and unencumbered software released into the public domain.
|
|
// For more information, see <https://unlicense.org>
|
|
//
|
|
|
|
import Testing
|
|
import Foundation
|
|
@testable import BitFoundation
|
|
|
|
struct Base64URLCodingTests {
|
|
@Test
|
|
func encodeUsesURLAlphabetWithoutPadding() {
|
|
// 0xFF 0xEF is "/+8=" in standard base64: exercises both
|
|
// substituted characters and padding removal.
|
|
#expect(Base64URLCoding.encode(Data([0xFF, 0xEF])) == "_-8")
|
|
#expect(Base64URLCoding.encode(Data("Man".utf8)) == "TWFu")
|
|
#expect(Base64URLCoding.encode(Data("Ma".utf8)) == "TWE")
|
|
#expect(Base64URLCoding.encode(Data("M".utf8)) == "TQ")
|
|
#expect(Base64URLCoding.encode(Data()) == "")
|
|
}
|
|
|
|
@Test
|
|
func decodeAcceptsUnpaddedInput() {
|
|
#expect(Base64URLCoding.decode("_-8") == Data([0xFF, 0xEF]))
|
|
#expect(Base64URLCoding.decode("TWFu") == Data("Man".utf8))
|
|
#expect(Base64URLCoding.decode("TWE") == Data("Ma".utf8))
|
|
#expect(Base64URLCoding.decode("TQ") == Data("M".utf8))
|
|
#expect(Base64URLCoding.decode("") == Data())
|
|
}
|
|
|
|
@Test
|
|
func decodeAcceptsPaddedInput() {
|
|
// External producers (e.g. Cashu wallets) emit padded forms too.
|
|
#expect(Base64URLCoding.decode("_-8=") == Data([0xFF, 0xEF]))
|
|
#expect(Base64URLCoding.decode("TWE=") == Data("Ma".utf8))
|
|
#expect(Base64URLCoding.decode("TQ==") == Data("M".utf8))
|
|
}
|
|
|
|
@Test
|
|
func decodeRejectsInvalidInput() {
|
|
// Length ≡ 1 (mod 4) can never be valid base64.
|
|
#expect(Base64URLCoding.decode("TQQQQ") == nil)
|
|
// Characters outside the base64url alphabet.
|
|
#expect(Base64URLCoding.decode("!!!") == nil)
|
|
#expect(Base64URLCoding.decode("TW Fu") == nil)
|
|
}
|
|
|
|
@Test
|
|
func roundTripsAllPaddingLengths() {
|
|
for length in 0..<16 {
|
|
let data = Data((0..<length).map { UInt8($0 &* 37 &+ 11) })
|
|
let encoded = Base64URLCoding.encode(data)
|
|
#expect(!encoded.contains("+"))
|
|
#expect(!encoded.contains("/"))
|
|
#expect(!encoded.contains("="))
|
|
#expect(Base64URLCoding.decode(encoded) == data)
|
|
}
|
|
}
|
|
}
|