-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
244 lines (193 loc) · 6.08 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
//
// SPDX-FileCopyrightText: Copyright 2024 Frank Schwab
//
// SPDX-License-Identifier: Apache-2.0
//
// SPDX-FileType: SOURCE
//
// Licensed under the Apache License, Version 2.0 (the "License");
// You may not use this file except in compliance with the License.
//
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Frank Schwab
//
// Version: 0.81.2
//
package main
import (
"filesigner/cmdline"
"filesigner/filehelper"
"filesigner/logger"
"fmt"
"os"
"runtime"
"strings"
)
// ******** Private constants ********
// myName contains the program name.
var myName string
// myVersion contains the program version.
const myVersion = `0.81.2`
// ******** Formal main function ********
// main is the main function and only a stub for a real main function.
func main() {
myName = filehelper.GetRealBaseName(os.Args[0])
// Hack, so that we have a way to have args as arguments, set the exit code and run defer functions.
// This is a severe design deficiency of Go 1
os.Exit(mainWithReturnCode(os.Args[1:]))
}
// Private constants
// Return codes
const (
rcOK = 0
rcCommandLineError = 1
rcProcessWarning = 2
rcProcessError = 3
)
// Command verbs
const (
commandHelp = `help`
commandSign = `sign`
commandVerify = `verify`
)
// ******** More private variables ********
// Program information
// scl contains the command line interpreter for the "sign" command.
var scl = cmdline.NewSignCommandLine()
// vcl contains the command line interpreter for the "verify" command.
var vcl = cmdline.NewVerifyCommandLine()
// ******** Real main function ********
// mainWithReturnCode is the real main function with arguments and return code.
// args do not include the program name, only the arguments.
func mainWithReturnCode(args []string) int {
printVersion()
argLen := len(args)
if argLen < 1 {
return printNotEnoughArgumentsError()
}
command := strings.ToLower(args[0])
switch command {
case commandHelp:
printUsageText()
return rcOK
case commandSign:
if argLen < 2 {
return printMissingContextId()
}
contextId := args[1]
if len(contextId) == 0 {
logger.PrintError(11, `Context id must not be empty`)
}
rc := processCmdLineArguments(scl, args[2:], argLen)
if rc != rcOK {
return rc
}
if len(scl.FileList) == 0 {
logger.PrintWarning(12, `No files found to sign`)
return rcProcessWarning
}
return doSigning(scl.SignaturesFileName, scl.SignatureType, contextId, scl.FileList)
case commandVerify:
rc := processCmdLineArguments(vcl, args[1:], argLen)
if rc != rcOK {
return rc
}
return doVerification(vcl.SignaturesFileName)
default:
return printUsageErrorf(13, `Unknown command: '%s'`, command)
}
}
// ******** Private functions ********
// processCmdLineArguments processes a cmdline.CommandLiner.
func processCmdLineArguments(cl cmdline.CommandLiner, args []string, argLen int) int {
err, isHelp := cl.Parse(args)
if isHelp {
return rcOK
}
if err != nil {
return printCommandLineParsingError(err)
}
err = cl.ExtractCommandData()
if err != nil {
logger.PrintErrorf(14, `Error getting data from command line: %v`, err)
return rcProcessError
}
return rcOK
}
// printVersion prints the program version information.
func printVersion() {
logger.PrintInfof(15, `%s V%s (%s, %d cpus)`,
myName,
myVersion,
runtime.Version(),
runtime.NumCPU())
}
// printNotEnoughArgumentsError prints an error message that the there are not enough arguments.
func printNotEnoughArgumentsError() int {
return printUsageError(15, `Not enough arguments`)
}
// printMissingContextId prints an error message that the context id is missing.
func printMissingContextId() int {
return printUsageError(16, `Context id missing`)
}
// printCommandLineParsingError prints an error message when there was in error in the command line parsing.
func printCommandLineParsingError(err error) int {
return printUsageErrorf(17, `Error parsing command line: %v`, err)
}
// printUsageError prints an error message followed by the usage message.
func printUsageError(msgNum byte, msgText string) int {
logger.PrintError(msgNum, msgText)
printUsageText()
return rcCommandLineError
}
// printUsageErrorf prints an error message followed by the usage message with a format string.
func printUsageErrorf(msgNum byte, msgFormat string, args ...any) int {
logger.PrintErrorf(msgNum, msgFormat, args...)
printUsageText()
return rcCommandLineError
}
// printUsageText prints the usage text.
func printUsageText() {
_, _ = fmt.Print(`
Usage:
Create and verify signatures for a collection of files.
Sign files:
`)
_, _ = fmt.Printf(` %s sign {contextId} [flags] [files]`, myName)
_, _ = fmt.Print(`
with 'files' being an optional list of file names and 'flags' one or more of the following options:
`)
scl.PrintUsage()
_, _ = fmt.Print(`
The 'contextId' is an arbitrary word used to make the signature depend on a topic, also called a 'domain separator'.
If no file names are specified, all files in the current directory are signed.
This can be modified by the exclude and include options.
The '--recurse' option is only valid if there are either no files specified or if there are include options present.
The files must be present in the current directory or one of its subdirectories.
Specifying a file outside the current directory tree is an error.
All file names that contain wildcards ('*', '?') are treated as if they were specified in an '--include-file' option.
Verify files:
`)
_, _ = fmt.Printf(` %s verify [flag]`, myName)
_, _ = fmt.Print(`
with 'flag' being the following:
`)
vcl.PrintUsage()
_, _ = fmt.Print(`
All the files in the signatures file will be verified.
Help:
`)
_, _ = fmt.Printf(` %s help`, myName)
_, _ = fmt.Print(`
Print this usage information.
`)
}