// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

package stun

import (
	
	
)

// FingerprintAttr represents FINGERPRINT attribute.
//
// RFC 5389 Section 15.5
type FingerprintAttr struct{}

// ErrFingerprintMismatch means that computed fingerprint differs from expected.
var ErrFingerprintMismatch = errors.New("fingerprint check failed")

// Fingerprint is shorthand for FingerprintAttr.
//
// Example:
//
//	m := New()
//	Fingerprint.AddTo(m)
var Fingerprint FingerprintAttr //nolint:gochecknoglobals

const (
	fingerprintXORValue uint32 = 0x5354554e //nolint:staticcheck
	fingerprintSize            = 4          // 32 bit
)

// FingerprintValue returns CRC-32 of b XOR-ed by 0x5354554e.
//
// The value of the attribute is computed as the CRC-32 of the STUN message
// up to (but excluding) the FINGERPRINT attribute itself, XOR'ed with
// the 32-bit value 0x5354554e (the XOR helps in cases where an
// application packet is also using CRC-32 in it).
func ( []byte) uint32 {
	return crc32.ChecksumIEEE() ^ fingerprintXORValue // XOR
}

// AddTo adds fingerprint to message.
func (FingerprintAttr) ( *Message) error {
	 := .Length
	// length in header should include size of fingerprint attribute
	.Length += fingerprintSize + attributeHeaderSize // increasing length
	.WriteLength()                                   // writing Length to Raw
	 := make([]byte, fingerprintSize)
	 := FingerprintValue(.Raw)
	bin.PutUint32(, )
	.Length = 
	.Add(AttrFingerprint, )
	return nil
}

// Check reads fingerprint value from m and checks it, returning error if any.
// Can return *AttrLengthErr, ErrAttributeNotFound, and *CRCMismatch.
func (FingerprintAttr) ( *Message) error {
	,  := .Get(AttrFingerprint)
	if  != nil {
		return 
	}
	if  = CheckSize(AttrFingerprint, len(), fingerprintSize);  != nil {
		return 
	}
	 := bin.Uint32()
	 := len(.Raw) - (fingerprintSize + attributeHeaderSize)
	 := FingerprintValue(.Raw[:])
	return checkFingerprint(, )
}