xhssign

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 13, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package xhssign builds the signed request headers that Xiaohongshu's web API (edith.xiaohongshu.com) requires: x-s, x-t, x-s-common, x-b3-traceid and x-xray-traceid.

The scheme here is reverse-engineered from the public xiaohongshu.com web client. It is reimplemented in Go from the algorithm description; no upstream code is copied. Xiaohongshu rotates this scheme from time to time, so when the API starts rejecting requests the fix lives entirely in this package and its tests.

The signing path is the modern XYW format. The older XYS format is rejected with HTTP 406 by the data endpoints (user_posted, otherinfo and friends), so XYW is the only path implemented.

Index

Constants

View Source
const (

	// DefaultAppID is the web client's application identifier.
	DefaultAppID = "xhs-pc-web"

	// PublicUserAgent is the desktop Chrome identifier the fingerprint is built
	// against. The signed fingerprint and the request's User-Agent should agree.
	PublicUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"
)

Fixed constants of the web scheme. These are not secrets; they are the same values the browser ships.

Variables

This section is empty.

Functions

func ContentString

func ContentString(method, uri string, params map[string]string, body string) string

ContentString builds the string the x-s payload hashes over. For GET it is the path plus an ordered query; for POST it is the path concatenated with the compact JSON body.

func GenerateA1

func GenerateA1(now time.Time, rnd func(n int) []byte) string

GenerateA1 builds a synthetic a1 cookie value, the 52-character device token the browser would otherwise be issued. It is used only when the homepage bootstrap does not set a1 (a blocked IP, for instance). The shape is hex(ms) + 30 random [a-z0-9] + "50000" + crc32, truncated to 52 chars.

func WebID

func WebID(a1 string) string

WebID derives the webId cookie from a1: the md5 of a1 in hex.

Types

type Headers

type Headers struct {
	XS          string
	XT          string
	XSCommon    string
	B3TraceID   string
	XrayTrace   string
	XYDirection string
}

Headers is the signed header set for one request.

func (Headers) Map

func (h Headers) Map() map[string]string

Map renders the headers as an http header map.

type Request

type Request struct {
	Method  string            // GET or POST
	URI     string            // path only, e.g. /api/sns/web/v1/feed
	Params  map[string]string // GET query params, in caller-supplied order via ParamOrder
	Body    string            // POST body, already compact JSON
	A1      string            // a1 cookie value
	Cookies map[string]string // full cookie set, for x-s-common
	AppID   string            // defaults to DefaultAppID
}

Request describes what to sign.

type Signer

type Signer struct {
	// NowMillis returns the current time in milliseconds. Tests override it.
	NowMillis func() int64
	// Rand returns n bytes of randomness. Tests override it.
	Rand func(n int) []byte
}

Signer holds the injectable clock and randomness so tests are deterministic.

func New

func New() *Signer

New returns a Signer using the real clock and crypto randomness.

func (*Signer) Sign

func (s *Signer) Sign(req Request) Headers

Sign produces the full header set for req at the given content string.

Jump to

Keyboard shortcuts

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