1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5package main
 6
 7import (
 8	"fmt"
 9	"strings"
10	"unicode"
11)
12
13func validateTrailer(trailer string) error {
14	if trailer == "" {
15		return fmt.Errorf("trailer cannot be empty")
16	}
17
18	lines := strings.Split(trailer, "\n")
19	firstLine := lines[0]
20
21	if len(firstLine) > 0 && unicode.IsSpace(rune(firstLine[0])) {
22		return fmt.Errorf("trailer key cannot start with whitespace: %q", trailer)
23	}
24
25	colonIdx := strings.Index(firstLine, ":")
26	if colonIdx == -1 {
27		return fmt.Errorf("trailer must contain ':' separator: %q", trailer)
28	}
29
30	key := firstLine[:colonIdx]
31
32	if strings.TrimSpace(key) != key {
33		return fmt.Errorf("trailer key cannot have leading or trailing whitespace: %q", key)
34	}
35
36	if strings.ContainsAny(key, " \t") {
37		return fmt.Errorf("trailer key cannot contain whitespace: %q", key)
38	}
39
40	if key == "" {
41		return fmt.Errorf("trailer key cannot be empty: %q", trailer)
42	}
43
44	for i, line := range lines[1:] {
45		if line == "" {
46			continue
47		}
48		if len(line) > 0 && !unicode.IsSpace(rune(line[0])) {
49			return fmt.Errorf("trailer continuation line %d must start with whitespace: %q", i+2, line)
50		}
51	}
52
53	return nil
54}
55
56func buildTrailersBlock(trailers []string) (string, error) {
57	if len(trailers) == 0 {
58		return "", nil
59	}
60
61	for _, trailer := range trailers {
62		if err := validateTrailer(trailer); err != nil {
63			return "", err
64		}
65	}
66
67	return strings.Join(trailers, "\n"), nil
68}