temari

package module
v0.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 1, 2026 License: MIT Imports: 9 Imported by: 0

README

temari — Go package (purego, no cgo)

中文版 README.md

temari calls the Temari cdylib (libtemari.so / .dylib / temari.dll) from pure Go and decrypts Apple Music FairPlay SAMPLE-AES samples directly inside a Go process.

This package does no networking: the template is fetched by the caller (e.g. pull the 40020 JSON response body with net/http) and handed to FromJSON for parsing.

No cgo required: all calls go through purego, so CGO_ENABLED=0 builds, tests, and runs work on Linux, macOS, and Windows.

Install

go get github.com/WorldObservationLog/Temari/bindings/go@v0.5.1

The module ships the cdylibs for all platforms under lib/<platform>/, and LoadDefault() selects the right one for the current GOOS/GOARCH — no Rust toolchain needed on the target machine. The Rust source is also embedded (crate/), so on an un-precompiled platform LoadDefault() compiles it on first use with cargo (cached under the user cache dir).

Usage

# (optional) build the cdylib from the repo instead of using the bundled one
cd <temari repo root>
cargo build --release        # artifact target/release/libtemari.so

# run examples and tests (CGO_ENABLED=0 works)
cd bindings/go
go run ./examples/json_decrypt.go      # auto-starts a mock 40020 (caller fetches JSON)
go run ./examples/json_decrypt.go --no-mock --json <template.json>   # offline
go test ./... -v
import "temari"

lib, err := temari.LoadDefault()   // bundled cdylib for the current platform

// 1) caller owns networking: fetch the 40020-style JSON response body (or read a local JSON file)
//    body, _ := fetchJSON(server, adamID, uri)   // net/http

// 2) the library only parses JSON -> template
t, err := lib.FromJSON(body)

plain, err := t.Decrypt(sample)          // single sample (equal-length plaintext)
plains, err := t.DecryptPar(samples)     // parallel batch, order preserved

t.Close()                                // free the handle

// streaming: submit samples as they arrive, receive in submission order
s, _ := t.NewStream(256)
s.Submit(chunk1); s.Submit(chunk2); s.Finish()
for plain := range s.C() { ... }          // goroutine + channel async
s.Close()

Notes

  • Symbols are bound at Load time; a missing symbol returns an error.
  • Handles must be released with Close().
  • Batch decryption treats each sample as an independent SAMPLE-AES unit (state resets per sample); clients should split samples on fragment/stripe boundaries.

Mapping to the FFI

Go API FFI export
Library.FromJSON tmpl_from_json
Temari.Decrypt decrypt_sample_ffi
Temari.DecryptPar decrypt_samples_par
Temari.NewStream / Stream stream_new/stream_submit/stream_next/...
Temari.Close tmpl_destroy

Documentation

Overview

Package temari wraps the Temari cdylib (libtemari.so / .dylib / temari.dll) with a cgo-free FFI. No C toolchain is required: the package builds and runs with CGO_ENABLED=0, for static binaries and cross-compilation.

The library performs **no network requests**: construct a template from a 40020-style key-server JSON response body with FromJSON — fetch the JSON yourself (own HTTP client) and pass it here.

Loading is platform-specific (see loader_unix.go / loader_windows.go):

  • Linux / macOS / FreeBSD: purego `Dlopen` to open the library
  • Windows: `golang.org/x/sys/windows` `LoadDLL` to open the library (purego supports Windows, but has no `Dlopen` there)

On every platform symbols are bound with purego `RegisterLibFunc` (its loadSymbol is dlopen/dlsym on unix, GetProcAddress on Windows), and all calls go through purego's cgo-free calling convention.

Build the library first:

cd <temari repo> && cargo build --release   # -> libtemari.so / temari.dll

Then load it once:

lib, err := temari.Load("/path/to/libtemari.so")   // or temari.dll on Windows
t, err := lib.FromJSON(jsonBody)                    // caller fetched the JSON
plain, err := t.Decrypt(sample)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BundledLibraryPath added in v0.2.0

func BundledLibraryPath() (string, error)

BundledLibraryPath returns the path of the cdylib bundled with this module for the current platform, or an error if none is present.

Types

type Library

type Library struct {
	// contains filtered or unexported fields
}

Library is the loaded temari cdylib. Call Load once and reuse the returned Library. `handle` is the module handle (dlopen on unix; LoadLibrary on Windows).

func Load

func Load(path string) (*Library, error)

Load opens the temari cdylib from path. Returns an error if the library or any required symbol is missing.

func LoadDefault added in v0.2.0

func LoadDefault() (*Library, error)

LoadDefault loads the cdylib bundled with this module for the current platform. For un-precompiled platforms it falls back to compiling the embedded Rust source with `cargo` (cached under the user cache dir). Prefer it over Load(path) when using the distributed package.

func (*Library) FromJSON

func (l *Library) FromJSON(json []byte) (*Temari, error)

FromJSON builds a template handle from a 40020-style key-server JSON response body. The library performs no network requests — fetch the JSON yourself (e.g. with net/http) and pass the raw body here.

type Stream

type Stream struct {
	// contains filtered or unexported fields
}

Stream is an incremental parallel decryptor with in-order results.

Submit encrypted samples as they arrive, then receive plaintexts in submission order. Blocking at the library level; wrap with C() for asynchronous consumption (goroutine + channel).

func (*Stream) C

func (s *Stream) C() <-chan []byte

C returns a channel that receives plaintexts in order until the stream is closed (the channel is then closed). A pump goroutine does the blocking Next() calls off the caller's goroutine.

func (*Stream) Close

func (s *Stream) Close()

Close destroys the stream handle (idempotent).

func (*Stream) Finish

func (s *Stream) Finish()

Finish closes the input side; already-submitted samples still drain.

func (*Stream) Next

func (s *Stream) Next() (plain []byte, ok bool)

Next blocks for the next plaintext (in order). ok=false once the stream is closed and everything is consumed.

func (*Stream) Submit

func (s *Stream) Submit(sample []byte) error

Submit queues one encrypted sample (blocks on internal backpressure).

func (*Stream) TryNext

func (s *Stream) TryNext() (plain []byte, state StreamState)

TryNext is a non-blocking probe.

type StreamState

type StreamState int

StreamState is the result of a non-blocking Stream.TryNext.

const (
	// StreamData: a plaintext is ready.
	StreamData StreamState = iota
	// StreamEmpty: no plaintext pending yet (stream still open).
	StreamEmpty
	// StreamClosed: the stream is closed and consumed.
	StreamClosed
)

type Temari

type Temari struct {
	// contains filtered or unexported fields
}

Temari is an opaque decryption template handle. Thread-safe for concurrent Decrypt calls; free with Close.

func (*Temari) Close

func (t *Temari) Close()

Close frees the template handle (nil-safe, idempotent).

func (*Temari) Decrypt

func (t *Temari) Decrypt(sample []byte) ([]byte, error)

Decrypt decrypts one sample, returning equal-length plaintext.

func (*Temari) DecryptPar

func (t *Temari) DecryptPar(samples [][]byte) ([][]byte, error)

DecryptPar decrypts a batch of independent samples in parallel, preserving order. Each sample is an independent SAMPLE-AES unit (state resets per sample), so a whole stream can be split at fragment boundaries and decrypted across all cores.

Default fast path: samples are read via scattered pointers (no input join memcpy) by decrypt_samples_par; plaintexts land in one flat buffer which is sliced into the returned views.

func (*Temari) NewStream

func (t *Temari) NewStream(batchSize int) (*Stream, error)

NewStream creates a streaming decryptor over this template. The stream clones the template, so the Temari handle may be closed afterwards. batchSize <= 0 selects a default of 256.

Directories

Path Synopsis
bench — temari Go 绑定(purego)性能基准, Linux / Windows 通用。
bench — temari Go 绑定(purego)性能基准, Linux / Windows 通用。
json_decrypt.go — temari Go 包完整示例。
json_decrypt.go — temari Go 包完整示例。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL