Full Mattermost server source with integrated Community Enterprise features. Includes vendor directory for offline/air-gapped builds. Structure: - enterprise-impl/: Enterprise feature implementations - enterprise-community/: Init files that register implementations - enterprise/: Bridge imports (community_imports.go) - vendor/: All dependencies for offline builds Build (online): go build ./cmd/mattermost Build (offline/air-gapped): go build -mod=vendor ./cmd/mattermost 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
166 lines
3.6 KiB
Go
166 lines
3.6 KiB
Go
package rardecode
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"io"
|
|
)
|
|
|
|
// cipherBlockReader implements Block Mode decryption of an io.Reader object.
|
|
type cipherBlockReader struct {
|
|
br byteReader
|
|
mode cipher.BlockMode
|
|
inbuf []byte // raw input blocks not yet decrypted
|
|
outbuf []byte // output buffer used when output slice < block size
|
|
block []byte // input/output buffer for a single block
|
|
}
|
|
|
|
func (cr *cipherBlockReader) fillOutbuf() error {
|
|
l := len(cr.inbuf)
|
|
_, err := io.ReadFull(cr.br, cr.block[l:])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cr.mode.CryptBlocks(cr.block, cr.block)
|
|
cr.outbuf = cr.block
|
|
return nil
|
|
}
|
|
|
|
func (cr *cipherBlockReader) ReadByte() (byte, error) {
|
|
if len(cr.outbuf) == 0 {
|
|
err := cr.fillOutbuf()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
b := cr.outbuf[0]
|
|
cr.outbuf = cr.outbuf[1:]
|
|
return b, nil
|
|
}
|
|
|
|
// Read reads and decrypts data into p.
|
|
// If the input is not a multiple of the cipher block size,
|
|
// the trailing bytes will be ignored.
|
|
func (cr *cipherBlockReader) Read(p []byte) (int, error) {
|
|
var n int
|
|
if len(cr.outbuf) > 0 {
|
|
n = copy(p, cr.outbuf)
|
|
cr.outbuf = cr.outbuf[n:]
|
|
return n, nil
|
|
}
|
|
blockSize := cr.mode.BlockSize()
|
|
if len(p) < blockSize {
|
|
// use cr.block as buffer
|
|
err := cr.fillOutbuf()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
n = copy(p, cr.outbuf)
|
|
cr.outbuf = cr.outbuf[n:]
|
|
return n, nil
|
|
}
|
|
// use p as buffer (but round down to multiple of block size)
|
|
p = p[:len(p)-(len(p)%blockSize)]
|
|
l := len(cr.inbuf)
|
|
if l > 0 {
|
|
copy(p, cr.inbuf)
|
|
cr.inbuf = nil
|
|
}
|
|
n, err := io.ReadAtLeast(cr.br, p[l:], blockSize-l)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
n += l
|
|
p = p[:n]
|
|
n -= n % blockSize
|
|
if n != len(p) {
|
|
l = copy(cr.block, p[n:])
|
|
cr.inbuf = cr.block[:l]
|
|
p = p[:n]
|
|
}
|
|
cr.mode.CryptBlocks(p, p)
|
|
return n, nil
|
|
}
|
|
|
|
func (cr *cipherBlockReader) writeToN(w io.Writer, n int64) (int64, error) {
|
|
if n == 0 {
|
|
return 0, nil
|
|
}
|
|
var tot int64
|
|
var err error
|
|
for tot != n && err == nil {
|
|
if len(cr.outbuf) == 0 {
|
|
err = cr.fillOutbuf()
|
|
if err != nil {
|
|
break
|
|
}
|
|
}
|
|
buf := cr.outbuf
|
|
if n > 0 {
|
|
todo := n - tot
|
|
if todo < int64(len(buf)) {
|
|
buf = buf[:todo]
|
|
}
|
|
}
|
|
var l int
|
|
l, err = w.Write(buf)
|
|
tot += int64(l)
|
|
cr.outbuf = cr.outbuf[l:]
|
|
}
|
|
if n < 0 && err == io.EOF {
|
|
err = nil
|
|
}
|
|
return tot, err
|
|
}
|
|
|
|
func (cr *cipherBlockReader) WriteTo(w io.Writer) (int64, error) {
|
|
return cr.writeToN(w, -1)
|
|
}
|
|
|
|
func newCipherBlockReader(r byteReader, mode cipher.BlockMode) *cipherBlockReader {
|
|
return &cipherBlockReader{
|
|
br: r,
|
|
mode: mode,
|
|
block: make([]byte, mode.BlockSize()),
|
|
}
|
|
}
|
|
|
|
// newAesDecryptReader returns a cipherBlockReader that decrypts input from a given io.Reader using AES.
|
|
func newAesDecryptReader(r byteReader, key, iv []byte) (*cipherBlockReader, error) {
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
mode := cipher.NewCBCDecrypter(block, iv)
|
|
return newCipherBlockReader(r, mode), nil
|
|
}
|
|
|
|
type cipherBlockFileReader struct {
|
|
archiveFile
|
|
cbr *cipherBlockReader
|
|
}
|
|
|
|
func (cr *cipherBlockFileReader) ReadByte() (byte, error) {
|
|
return cr.cbr.ReadByte()
|
|
}
|
|
|
|
func (cr *cipherBlockFileReader) Read(p []byte) (int, error) {
|
|
return cr.cbr.Read(p)
|
|
}
|
|
|
|
func (cr *cipherBlockFileReader) WriteTo(w io.Writer) (int64, error) {
|
|
return cr.cbr.WriteTo(w)
|
|
}
|
|
|
|
func (cr *cipherBlockFileReader) writeToN(w io.Writer, n int64) (int64, error) {
|
|
return cr.cbr.writeToN(w, n)
|
|
}
|
|
|
|
func newAesDecryptFileReader(r archiveFile, key, iv []byte) (*cipherBlockFileReader, error) {
|
|
cbr, err := newAesDecryptReader(r, key, iv)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &cipherBlockFileReader{archiveFile: r, cbr: cbr}, nil
|
|
}
|