- Fix issue #94

- Fix linter
- Remove useless code/deadcode
This commit is contained in:
Nicolas JUHEL
2021-04-13 13:08:49 +02:00
parent 499b5ee613
commit dbb443eb65
48 changed files with 673 additions and 1418 deletions

View File

@@ -20,13 +20,14 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.14
go-version: ^1.16
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Link workspace with GOPATH
continue-on-error: false
run: |
sudo mkdir -vp $(dirname ${GOPATH}/src/github.com/${GITHUB_REPOSITORY})
sudo chown -R ${USER}:users $(dirname ${GOPATH}/src/github.com/${GITHUB_REPOSITORY})
@@ -34,17 +35,19 @@ jobs:
sudo ln -svf $(pwd) ${GOPATH}/src/github.com/${GITHUB_REPOSITORY}
- name: Check out tools into the Go module directory
continue-on-error: false
run: |
git clone https://github.com/nabbar/gotools.git scripts
./scripts/prepare
- name: Update vendor or dependancies
continue-on-error: false
run: ./scripts/ci_depend
- name: Check goFmt & goImport
continue-on-error: false
run: ./scripts/ci_format
- name: Update vendor or dependancies
run: ./scripts/ci_depend
- name: Check Missing License
continue-on-error: false
run: ./scripts/ci_license

View File

@@ -1,23 +1,88 @@
# This file contains all available configuration options
# with their default values.
linters-settings:
dupl:
threshold: 100
funlen:
lines: 250
statements: 200
gci:
local-prefixes: github.com/golangci/golangci-lint
goconst:
min-len: 2
min-occurrences: 2
gocyclo:
min-complexity: 50
goimports:
local-prefixes: github.com/golangci/golangci-lint
gomnd:
settings:
mnd:
# don't include the "operation" and "assign"
checks: argument,case,condition,return
govet:
check-shadowing: true
settings:
printf:
funcs:
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
lll:
line-length: 140
maligned:
suggest-new: true
misspell:
locale: US
linters:
# please, do not use `enable-all`: it's deprecated and will be removed soon.
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
disable-all: true
enable:
- bodyclose
- deadcode
- dogsled
- dupl
- errcheck
- exportloopref
- exhaustive
- funlen
- goconst
- gocyclo
- gofmt
- goimports
- gomnd
- goprintffuncname
- gosec
- gosimple
- govet
- ineffassign
- lll
- misspell
- nakedret
- noctx
- rowserrcheck
- staticcheck
- structcheck
- stylecheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
# options for analysis running
run:
# default concurrency is a available CPU number
concurrency: 4
#concurrency: 4
# timeout for analysis, e.g. 30s, 5m, default is 1m
timeout: 30m
timeout: 10m
# exit code when at least one issue was found, default is 1
issues-exit-code: 0
issues-exit-code: 1
# include test files or not, default is true
tests: true
tests: false
# list of build tags, all linters use it. Default is empty list.
build-tags: []
#build-tags:
# - mytag
# which dirs to skip: issues from them won't be reported;
# can use regexp here: generated.*, regexp is applied on full path;
# default value is empty list, but default dirs are skipped independently
@@ -25,22 +90,21 @@ run:
# "/" will be replaced by current OS file path separator to properly work
# on Windows.
skip-dirs:
- vendor
- test
- test/
- vendor/
- .*
# default is true. Enables skipping of directories:
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
skip-dirs-use-default: true
#skip-dirs-use-default: true
# which files to skip: they will be analyzed, but issues from them
# won't be reported. Default value is empty list, but there is
# no need to include all autogenerated files, we confidently recognize
# autogenerated files. If it's not please let us know.
# "/" will be replaced by current OS file path separator to properly work
# on Windows.
skip-files:
- ".*\\.my\\.go$"
#skip-files:
# - ".*\\.my\\.go$"
# - lib/bad.go
# by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules":
# If invoked with -mod=readonly, the go command is disallowed from the implicit
# automatic updating of go.mod described above. Instead, it fails when any changes
@@ -49,401 +113,20 @@ run:
# If invoked with -mod=vendor, the go command assumes that the vendor
# directory holds the correct copies of dependencies and ignores
# the dependency descriptions in go.mod.
#modules-download-mode: readonly|release|vendor
modules-download-mode: vendor
# Allow multiple parallel golangci-lint instances running.
# If false (default) - golangci-lint acquires file lock on start.
allow-parallel-runners: false
allow-parallel-runners: true
# output configuration options
output:
# colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number"
format: colored-line-number
# print lines of code with issue, default is true
print-issued-lines: true
# print linter name in the end of issue text, default is true
print-linter-name: true
# make issues output unique by line, default is true
uniq-by-line: true
# add a prefix to the output file references; default is no prefix
path-prefix: ""
# all available settings of specific linters
linters-settings:
dogsled:
# checks assignments with too many blank identifiers; default is 2
max-blank-identifiers: 2
dupl:
# tokens count to trigger issue, 150 by default
threshold: 100
errcheck:
# report about not checking of errors in type assertions: `a := b.(MyStruct)`;
# default is false: such cases aren't reported by default.
check-type-assertions: false
# report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`;
# default is false: such cases aren't reported by default.
check-blank: false
# [deprecated] comma-separated list of pairs of the form pkg:regex
# the regex is used to ignore names within pkg. (default "fmt:.*").
# see https://github.com/kisielk/errcheck#the-deprecated-method for details
ignore: fmt:.*,io/ioutil:^Read.*
# path to a file containing a list of functions to exclude from checking
# see https://github.com/kisielk/errcheck#excluding-functions for details
# exclude: /path/to/file.txt
exhaustive:
# indicates that switch statements are to be considered exhaustive if a
# 'default' case is present, even if all enum members aren't listed in the
# switch
default-signifies-exhaustive: false
funlen:
lines: 1000
statements: 100
gocognit:
# minimal code complexity to report, 30 by default (but we recommend 10-20)
min-complexity: 50
nestif:
# minimal complexity of if statements to report, 5 by default
min-complexity: 4
goconst:
# minimal length of string constant, 3 by default
min-len: 3
# minimal occurrences count to trigger, 3 by default
min-occurrences: 3
gocritic:
# Which checks should be enabled; can't be combined with 'disabled-checks';
# See https://go-critic.github.io/overview#checks-overview
# To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run`
# By default list of stable checks is used.
# enabled-checks:
# - rangeValCopy
# Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty
disabled-checks:
- regexpMust
# Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks.
# Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags".
enabled-tags:
- performance
disabled-tags:
- experimental
settings: # settings passed to gocritic
captLocal: # must be valid enabled check name
paramsOnly: true
rangeValCopy:
sizeThreshold: 32
gocyclo:
# minimal code complexity to report, 30 by default (but we recommend 10-20)
min-complexity: 50
godot:
# check all top-level comments, not only declarations
check-all: false
godox:
# report any comments starting with keywords, this is useful for TODO or FIXME comments that
# might be left in the code accidentally and should be resolved before merging
keywords: # default keywords are TODO, BUG, and FIXME, these can be overwritten by this setting
- NOTE
- OPTIMIZE # marks code that should be optimized before merging
- HACK # marks hack-arounds that should be removed before merging
gofmt:
# simplify code: gofmt with `-s` option, true by default
simplify: true
goheader:
values:
const:
# define here const type values in format k:v, for example:
# YEAR: 2020
# COMPANY: MY COMPANY
regexp:
# define here regexp type values, for example
# AUTHOR: .*@mycompany\.com
template:
# put here copyright header template for source code files, for example:
# {{ AUTHOR }} {{ COMPANY }} {{ YEAR }}
# SPDX-License-Identifier: Apache-2.0
#
# 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.
template-path:
# also as alternative of directive 'template' you may put the path to file with the template source
goimports:
# put imports beginning with prefix after 3rd-party packages;
# it's a comma-separated list of prefixes
local-prefixes: github.com/org/project
golint:
# minimal confidence for issues, default is 0.8
min-confidence: 0.8
gomnd:
settings:
mnd:
# the list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description.
checks: argument,case,condition,operation,return,assign
gomodguard:
allowed:
modules: # List of allowed modules
# - gopkg.in/yaml.v2
domains: # List of allowed module domains
# - golang.org
blocked:
modules: # List of blocked modules
# - github.com/uudashr/go-module: # Blocked module
# recommendations: # Recommended modules that should be used instead (Optional)
# - golang.org/x/mod
# reason: "`mod` is the official go.mod parser library." # Reason why the recommended module should be used (Optional)
versions: # List of blocked module version constraints
# - github.com/mitchellh/go-homedir: # Blocked module with version constraint
# version: "< 1.1.0" # Version constraint, see https://github.com/Masterminds/semver#basic-comparisons
# reason: "testing if blocked version constraint works." # Reason why the version constraint exists. (Optional)
govet:
# report about shadowed variables
check-shadowing: true
# settings per analyzer
settings:
printf: # analyzer name, run `go tool vet help` to see all analyzers
funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
# enable or disable analyzers by name
enable:
- atomicalign
enable-all: false
disable:
- shadow
disable-all: false
depguard:
list-type: blacklist
include-go-root: false
packages:
# - github.com/sirupsen/logrus
packages-with-error-message:
# specify an error message to output when a blacklisted package is used
# - github.com/sirupsen/logrus: "logging is allowed only by logutils.Log"
lll:
# max line length, lines longer will be reported. Default is 120.
# '\t' is counted as 1 character by default, and can be changed with the tab-width option
line-length: 240
# tab width in spaces. Default to 1.
tab-width: 1
maligned:
# print struct with more effective memory layout or not, false by default
suggest-new: true
misspell:
# Correct spellings using locale preferences for US or UK.
# Default is to use a neutral variety of English.
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
locale: US
ignore-words:
- someword
nakedret:
# make an issue if func has more lines of code than this setting and it has naked returns; default is 30
max-func-lines: 30
prealloc:
# XXX: we don't recommend using this linter before doing performance profiling.
# For most programs usage of prealloc will be a premature optimization.
# Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them.
# True by default.
simple: true
range-loops: true # Report preallocation suggestions on range loops, true by default
for-loops: false # Report preallocation suggestions on for loops, false by default
nolintlint:
# Enable to ensure that nolint directives are all used. Default is true.
allow-unused: false
# Disable to ensure that nolint directives don't have a leading space. Default is true.
allow-leading-space: true
# Exclude following linters from requiring an explanation. Default is [].
allow-no-explanation: []
# Enable to require an explanation of nonzero length after each nolint directive. Default is false.
require-explanation: true
# Enable to require nolint directives to mention the specific linter being suppressed. Default is false.
require-specific: true
rowserrcheck:
packages:
- github.com/jmoiron/sqlx
testpackage:
# regexp pattern to skip files
skip-regexp: (export|internal)_test\.go
unparam:
# Inspect exported functions, default is false. Set to true if no external program/library imports your code.
# XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:
# if it's called for subdir of a project it can't find external interfaces. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
unused:
# treat code as a program (not a library) and report unused exported identifiers; default is false.
# XXX: if you enable this setting, unused will report a lot of false-positives in text editors:
# if it's called for subdir of a project it can't find funcs usages. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
whitespace:
multi-if: false # Enforces newlines (or comments) after every multi-line if statement
multi-func: false # Enforces newlines (or comments) after every multi-line function signature
wsl:
# If true append is only allowed to be cuddled if appending value is
# matching variables, fields or types on line above. Default is true.
strict-append: true
# Allow calls and assignments to be cuddled as long as the lines have any
# matching variables, fields or types. Default is true.
allow-assign-and-call: true
# Allow multiline assignments to be cuddled. Default is true.
allow-multiline-assign: true
# Allow declarations (var) to be cuddled.
allow-cuddle-declarations: true
# Allow trailing comments in ending of blocks
allow-trailing-comment: false
# Force newlines in end of case at this limit (0 = never).
force-case-trailing-whitespace: 0
# Force cuddling of err checks with err var assignment
force-err-cuddling: false
# Allow leading comments to be separated with empty liens
allow-separated-leading-comment: false
gofumpt:
# Choose whether or not to use the extra rules that are disabled
# by default
extra-rules: false
# The custom section can be used to define linter plugins to be loaded at runtime. See README doc
# for more info.
#custom:
# Each custom linter should have a unique name.
#example:
# The path to the plugin *.so. Can be absolute or local. Required for each custom linter
#path: /path/to/example.so
# The description of the linter. Optional, just for documentation purposes.
#description: This is an example usage of a plugin linter.
# Intended to point to the repo location of the linter. Optional, just for documentation purposes.
#original-url: github.com/golangci/example-linter
linters:
fast: false
enable-all: true
disable:
- gochecknoinits
- gochecknoglobals
- wsl
- golint
- gocritic
- stylecheck
- whitespace
- gofumpt
- nestif
- nolintlint
- nlreturn
issues:
# List of regexps of issue texts to exclude, empty list by default.
# But independently from this option we use default exclude patterns,
# it can be disabled by `exclude-use-default: false`. To list all
# excluded by default patterns execute `golangci-lint run --help`
exclude:
- .*test.*\.go
# Excluding configuration per-path, per-linter, per-text and per-source
exclude-rules:
# Exclude some linters from running on tests files.
- path: _test\.go
linters:
- gocyclo
- errcheck
- dupl
- gosec
# Exclude known linters from partially hard-vendored code,
# which is impossible to exclude via "nolint" comments.
- path: internal/hmac/
text: "weak cryptographic primitive"
linters:
- gosec
# Exclude some staticcheck messages
- linters:
- staticcheck
text: "SA9003:"
# Exclude lll issues for long lines with go:generate
- linters:
- lll
source: "^//go:generate "
# Independently from option `exclude` we use default exclude patterns,
# it can be disabled by this option. To list all
# excluded by default patterns execute `golangci-lint run --help`.
# Default value for this option is true.
exclude-use-default: false
# The default value is false. If set to true exclude and exclude-rules
# regular expressions become case sensitive.
exclude-case-sensitive: false
# The list of ids of default excludes to include or disable. By default it's empty.
include:
- EXC0002 # disable excluding of issues about comments from golint
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
max-issues-per-linter: 0
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
max-same-issues: 0
# Show only new issues: if there are unstaged changes or untracked files,
# only those changes are analyzed, else only changes in HEAD~ are analyzed.
# It's a super-useful option for integration of golangci-lint into existing
# large codebase. It's not practical to fix all existing issues at the moment
# of integration: much better don't allow issues in new code.
# Default is false.
new: false
# Show only new issues created after git revision `REV`
#new-from-rev: REV
# Show only new issues created in git patch with set file path.
#new-from-patch: path/to/patch/file
severity:
# Default value is empty string.
# Set the default severity for issues. If severity rules are defined and the issues
# do not match or no severity is provided to the rule this will be the default
# severity applied. Severities should match the supported severity names of the
# selected out format.
# - Code climate: https://docs.codeclimate.com/docs/issues#issue-severity
# - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#severity
# - Github: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message
default-severity: error
# The default value is false.
# If set to true severity-rules regular expressions become case sensitive.
case-sensitive: false
# Default value is empty list.
# When a list of severity rules are provided, severity information will be added to lint
# issues. Severity rules have the same filtering capability as exclude rules except you
# are allowed to specify one matcher per severity rule.
# Only affects out formats that support setting severity information.
rules:
- linters:
- dupl
severity: info

View File

@@ -43,11 +43,9 @@ import (
type ArchiveType uint8
const (
ArchiveTypeUnknown = iota
ArchiveTypeZip
ArchiveTypeTar
ArchiveTypeTarGzip
ArchiveTypeGzip
TypeTar = iota + 1
TypeTarGzip
TypeGzip
)
func ExtractFile(src, dst libiot.FileProgress, fileNameContain, fileNameRegex string) liberr.Error {
@@ -204,15 +202,16 @@ func ExtractAll(src libiot.FileProgress, originalName, outputPath string, defaul
func CreateArchive(archiveType ArchiveType, archive libiot.FileProgress, pathContent ...string) (created bool, err liberr.Error) {
//@TODO: make function
if len(pathContent) < 1 {
//nolint #goerr113
return false, ErrorParamsEmpty.ErrorParent(fmt.Errorf("pathContent is empty"))
}
switch archiveType {
case ArchiveTypeGzip:
case TypeGzip:
return libgzp.Create(archive, pathContent...)
case ArchiveTypeTar:
case TypeTar:
return libtar.Create(archive, pathContent...)
case ArchiveTypeTarGzip:
case TypeTarGzip:
return libtar.CreateGzip(archive, pathContent...)
}

View File

@@ -34,10 +34,9 @@ import (
"os"
liberr "github.com/nabbar/golib/errors"
libiot "github.com/nabbar/golib/ioutils"
)
func Create(archive libiot.FileProgress, content ...string) (bool, liberr.Error) {
func Create(archive io.WriteSeeker, content ...string) (bool, liberr.Error) {
var (
w *gzip.Writer
f *os.File
@@ -46,6 +45,7 @@ func Create(archive libiot.FileProgress, content ...string) (bool, liberr.Error)
)
if len(content) != 1 {
//nolint #goerr113
return false, ErrorParamsMismatching.ErrorParent(fmt.Errorf("content path must be limited to strictly one contents"))
}

View File

@@ -36,185 +36,125 @@ import (
"path/filepath"
liberr "github.com/nabbar/golib/errors"
libiot "github.com/nabbar/golib/ioutils"
)
func Create(archive libiot.FileProgress, content ...string) (bool, liberr.Error) {
func Create(archive io.WriteSeeker, content ...string) (bool, liberr.Error) {
var (
t *tar.Writer
n int64
err error
lEr = ErrorTarCreateAddFile.Error(nil)
)
if _, err = archive.Seek(0, io.SeekStart); err != nil {
if _, err := archive.Seek(0, io.SeekStart); err != nil {
return false, ErrorFileSeek.ErrorParent(err)
}
t = tar.NewWriter(archive)
for i := 0; i < len(content); i++ {
if content[i] == "" {
continue
if ok, err := createTar(archive, content...); err != nil || !ok {
return ok, err
}
err = filepath.Walk(content[i], func(file string, inf os.FileInfo, err error) error {
var (
e error
h *tar.Header
f *os.File
)
// generate tar header
h, e = tar.FileInfoHeader(inf, file)
if e != nil {
return e
}
// must provide real name
// (see https://golang.org/src/archive/tar/common.go?#L626)
h.Name = filepath.ToSlash(file)
// write header
if e = t.WriteHeader(h); err != nil {
return err
}
// if not a dir, write file content
if !inf.IsDir() {
f, e = os.Open(file)
if e != nil {
return e
}
if _, e = io.Copy(t, f); e != nil {
return e
}
}
n++
return nil
})
if err != nil {
lEr.AddParent(err)
continue
}
}
if n < 1 {
if lEr.HasParent() {
return false, lEr
}
return false, ErrorTarCreate.ErrorParent(fmt.Errorf("no file to add in archive"))
} else if !lEr.HasParent() {
lEr = nil
}
if err = t.Close(); err != nil {
return false, ErrorTarCreate.ErrorParent(err)
}
if _, err = archive.Seek(0, io.SeekStart); err != nil {
if _, err := archive.Seek(0, io.SeekStart); err != nil {
return false, ErrorFileSeek.ErrorParent(err)
}
return true, lEr
return true, nil
}
func CreateGzip(archive libiot.FileProgress, content ...string) (bool, liberr.Error) {
func CreateGzip(archive io.WriteSeeker, content ...string) (bool, liberr.Error) {
var (
z *gzip.Writer
t *tar.Writer
n int64
err error
lEr = ErrorTarCreateAddFile.Error(nil)
)
if _, err = archive.Seek(0, io.SeekStart); err != nil {
if _, err := archive.Seek(0, io.SeekStart); err != nil {
return false, ErrorFileSeek.ErrorParent(err)
}
z = gzip.NewWriter(archive)
t = tar.NewWriter(z)
z := gzip.NewWriter(archive)
for i := 0; i < len(content); i++ {
if content[i] == "" {
continue
if ok, err := createTar(z, content...); err != nil || !ok {
return ok, err
}
err = filepath.Walk(content[i], func(file string, inf os.FileInfo, err error) error {
var (
e error
h *tar.Header
f *os.File
)
// generate tar header
h, e = tar.FileInfoHeader(inf, file)
if e != nil {
return e
}
// must provide real name
// (see https://golang.org/src/archive/tar/common.go?#L626)
h.Name = filepath.ToSlash(file)
// write header
if e = t.WriteHeader(h); err != nil {
return err
}
// if not a dir, write file content
if !inf.IsDir() {
f, e = os.Open(file)
if e != nil {
return e
}
if _, e = io.Copy(t, f); e != nil {
return e
}
}
n++
return nil
})
if err != nil {
lEr.AddParent(err)
continue
}
}
if n < 1 {
if lEr.HasParent() {
return false, lEr
}
return false, ErrorTarCreate.ErrorParent(fmt.Errorf("no file to add in archive"))
} else if !lEr.HasParent() {
lEr = nil
}
if err = t.Close(); err != nil {
return false, ErrorTarCreate.ErrorParent(err)
}
if err = z.Close(); err != nil {
if err := z.Close(); err != nil {
return false, ErrorGzipCreate.ErrorParent(err)
}
if _, err = archive.Seek(0, io.SeekStart); err != nil {
if _, err := archive.Seek(0, io.SeekStart); err != nil {
return false, ErrorFileSeek.ErrorParent(err)
}
return true, nil
}
func createTar(w io.Writer, content ...string) (bool, liberr.Error) {
var (
t *tar.Writer
n int64
err error
lEr = ErrorTarCreateAddFile.Error(nil)
)
t = tar.NewWriter(w)
for i := 0; i < len(content); i++ {
if content[i] == "" {
continue
}
err = filepath.Walk(content[i], func(file string, inf os.FileInfo, err error) error {
var (
e error
h *tar.Header
f *os.File
)
// generate tar header
h, e = tar.FileInfoHeader(inf, file)
if e != nil {
return e
}
// must provide real name
// (see https://golang.org/src/archive/tar/common.go?#L626)
h.Name = filepath.ToSlash(file)
// write header
if e = t.WriteHeader(h); e != nil {
return e
}
// if not a dir, write file content
if !inf.IsDir() {
//nolint #gosec
/* #nosec */
f, e = os.Open(file)
if e != nil {
return e
}
if _, e = io.Copy(t, f); e != nil {
return e
}
}
n++
return nil
})
if err != nil {
lEr.AddParent(err)
continue
}
}
if n < 1 {
if lEr.HasParent() {
return false, lEr
}
//nolint #goerr113
return false, ErrorTarCreate.ErrorParent(fmt.Errorf("no file to add in archive"))
} else if !lEr.HasParent() {
lEr = nil
}
if err = t.Close(); err != nil {
return false, ErrorTarCreate.ErrorParent(err)
}
return true, lEr
}

View File

@@ -107,23 +107,14 @@ func (a *artifactoryModel) request(uri string, bodyResponse interface{}) liberr.
u *url.URL
)
//ctx, cnl = context.WithTimeout(a.ctx, libhtc.TIMEOUT_5_SEC)
ctx, cnl = context.WithCancel(a.ctx)
defer func() {
if cnl != nil {
cnl()
}
if rsp != nil && rsp.Body != nil {
_ = rsp.Body.Close()
}
if req != nil && req.Body != nil {
_ = req.Body.Close()
}
}()
//ctx, cnl = context.WithTimeout(a.ctx, libhtc.TIMEOUT_5_SEC)
ctx, cnl = context.WithCancel(a.ctx)
u = &url.URL{
Scheme: a.endpoint.Scheme,
Opaque: a.endpoint.Opaque,
@@ -149,15 +140,29 @@ func (a *artifactoryModel) request(uri string, bodyResponse interface{}) liberr.
return ErrorRequestInit.ErrorParent(e)
}
defer func() {
if req != nil && req.Body != nil {
_ = req.Body.Close()
}
}()
if rsp, e = a.Do(req); e != nil {
return ErrorRequestDo.ErrorParent(e)
}
if rsp.StatusCode >= 400 {
defer func() {
if rsp != nil && rsp.Body != nil {
_ = rsp.Body.Close()
}
}()
if rsp.StatusCode >= http.StatusBadRequest {
//nolint #goerr113
return ErrorRequestResponse.ErrorParent(fmt.Errorf("status: %v", rsp.Status))
}
if rsp.Body == nil {
//nolint #goerr113
return ErrorRequestResponseBodyEmpty.ErrorParent(fmt.Errorf("status: %v", rsp.Status))
}
@@ -181,10 +186,12 @@ func (a *artifactoryModel) getStorageList() (sto []ResponseStorage, err liberr.E
)
if a.regex == "" {
//nolint #goerr113
return nil, ErrorParamsEmpty.ErrorParent(fmt.Errorf("regex is empty: %s", a.regex))
}
if a.group < 1 {
//nolint #goerr113
return nil, ErrorParamsEmpty.ErrorParent(fmt.Errorf("group extracted from regex is empty: %s - %v", a.regex, a.group))
}
@@ -342,9 +349,11 @@ func (a *artifactoryModel) Download(dst libiot.FileProgress, containName string,
return ErrorRequestInit.ErrorParent(e)
} else if rsp, e = a.Do(req); e != nil {
return ErrorRequestDo.ErrorParent(e)
} else if rsp.StatusCode >= 400 {
} else if rsp.StatusCode >= http.StatusBadRequest {
//nolint #goerr113
return ErrorRequestResponse.ErrorParent(fmt.Errorf("status: %v", rsp.Status))
} else if rsp.Body == nil {
//nolint #goerr113
return ErrorRequestResponseBodyEmpty.ErrorParent(fmt.Errorf("status: %v", rsp.Status))
} else if _, e := dst.ReadFrom(rsp.Body); e != nil {
return ErrorArtifactoryDownload.ErrorParent(e)

View File

@@ -71,8 +71,6 @@ func TestGolibAwsHelper(t *testing.T) {
RunSpecs(t, "Aws Helper Suite")
}
const testRegion = "us-east-1"
var _ = BeforeSuite(func() {
var (
err error

View File

@@ -226,7 +226,7 @@ func (c *awsModel) ResolveEndpoint(service, region string) (sdkaws.Endpoint, err
}, nil
}
logger.DebugLevel.Logf("Called ResolveEndpoint for service / region '%s' with nil endpoint", service, region)
logger.DebugLevel.Logf("Called ResolveEndpoint for service '%s' / region '%s' with nil endpoint", service, region)
return sdkaws.Endpoint{}, ErrorEndpointInvalid.Error(nil)
}

View File

@@ -26,10 +26,13 @@
package object
import (
//nolint #nosec
/* #nosec */
"crypto/md5"
"encoding/base64"
"io"
//nolint #gci
"os"
sdkaws "github.com/aws/aws-sdk-go-v2/aws"
@@ -101,8 +104,8 @@ func (cli *client) MultipartPutCustom(partSize libhlp.PartSize, object string, b
/* #nosec */
h := md5.New()
if _, err := tmp.WriteTo(h); err != nil {
return cli.multipartCancel(err, upl.UploadId, object)
if _, e := tmp.WriteTo(h); e != nil {
return cli.multipartCancel(e, upl.UploadId, object)
}
_, err = tmp.Seek(0, io.SeekStart)

View File

@@ -42,6 +42,7 @@ const maxItemList int32 = 1000
func (cli *client) VersionList(arn string, maxItem int32) (map[string]string, liberr.Error) {
if arn == "" {
//nolint #goerr113
return nil, libhlp.ErrorParamsEmpty.ErrorParent(fmt.Errorf("arn is empty"))
}
@@ -51,7 +52,7 @@ func (cli *client) VersionList(arn string, maxItem int32) (map[string]string, li
var (
marker = ""
res = make(map[string]string, 0)
res = make(map[string]string)
)
for {

View File

@@ -39,12 +39,6 @@ type Certif struct {
}
type Config struct {
InheritDefault bool `mapstructure:"inheritDefault" json:"inheritDefault" yaml:"inheritDefault" toml:"inheritDefault"`
VersionMin string `mapstructure:"versionMin" json:"versionMin" yaml:"versionMin" toml:"versionMin"`
VersionMax string `mapstructure:"versionMax" json:"versionMax" yaml:"versionMax" toml:"versionMax"`
DynmaicSizingDisable bool `mapstructure:"dynamicSizingDisable" json:"dynamicSizingDisable" yaml:"dynamicSizingDisable" toml:"dynamicSizingDisable"`
SessionTicketDisable bool `mapstructure:"sessionTicketDisable" json:"sessionTicketDisable" yaml:"sessionTicketDisable" toml:"sessionTicketDisable"`
AuthClient string `mapstructure:"authClient" json:"authClient" yaml:"authClient" toml:"authClient"`
CurveList []string `mapstructure:"curveList" json:"curveList" yaml:"curveList" toml:"curveList"`
CipherList []string `mapstructure:"cipherList" json:"cipherList" yaml:"cipherList" toml:"cipherList"`
RootCAString []string `mapstructure:"rootCA" json:"rootCA" yaml:"rootCA" toml:"rootCA"`
@@ -53,6 +47,12 @@ type Config struct {
ClientCAFiles []string `mapstructure:"clientCAFiles" json:"clientCAFiles" yaml:"clientCAFiles" toml:"clientCAFiles"`
CertPairString []Certif `mapstructure:"certPair" json:"certPair" yaml:"certPair" toml:"certPair"`
CertPairFile []Certif `mapstructure:"certPairFiles" json:"certPairFiles" yaml:"certPairFiles" toml:"certPairFiles"`
VersionMin string `mapstructure:"versionMin" json:"versionMin" yaml:"versionMin" toml:"versionMin"`
VersionMax string `mapstructure:"versionMax" json:"versionMax" yaml:"versionMax" toml:"versionMax"`
AuthClient string `mapstructure:"authClient" json:"authClient" yaml:"authClient" toml:"authClient"`
InheritDefault bool `mapstructure:"inheritDefault" json:"inheritDefault" yaml:"inheritDefault" toml:"inheritDefault"`
DynamicSizingDisable bool `mapstructure:"dynamicSizingDisable" json:"dynamicSizingDisable" yaml:"dynamicSizingDisable" toml:"dynamicSizingDisable"`
SessionTicketDisable bool `mapstructure:"sessionTicketDisable" json:"sessionTicketDisable" yaml:"sessionTicketDisable" toml:"sessionTicketDisable"`
}
func (c *Config) Validate() liberr.Error {
@@ -64,6 +64,7 @@ func (c *Config) Validate() liberr.Error {
}
for _, err := range err.(valid.ValidationErrors) {
//nolint #goerr113
e.AddParent(fmt.Errorf("config field '%s' is not validated by constraint '%s'", err.StructNamespace(), err.ActualTag()))
}
}
@@ -83,6 +84,7 @@ func (c *Config) New() (TLSConfig, liberr.Error) {
}
}
//nolint #gocognit
func (c *Config) NewFrom(cfg TLSConfig) (TLSConfig, liberr.Error) {
var t *config
@@ -103,7 +105,7 @@ func (c *Config) NewFrom(cfg TLSConfig) (TLSConfig, liberr.Error) {
t.tlsMaxVersion = StringToTlsVersion(c.VersionMax)
}
if c.DynmaicSizingDisable {
if c.DynamicSizingDisable {
t.dynSizingDisabled = true
}

View File

@@ -80,47 +80,47 @@ func New() TLSConfig {
}
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func AddRootCAContents(rootContent string) bool {
return Default.AddRootCAString(rootContent)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func AddRootCAFile(rootFile string) liberr.Error {
return Default.AddRootCAFile(rootFile)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func AddCACertificateContents(caContent string) bool {
return Default.AddClientCAString(caContent)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func AddCACertificateFile(caFile string) liberr.Error {
return Default.AddClientCAFile(caFile)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func AddCertificatePairString(key, crt string) liberr.Error {
return Default.AddCertificatePairString(key, crt)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func AddCertificatePairFile(keyFile, crtFile string) liberr.Error {
return Default.AddCertificatePairFile(keyFile, crtFile)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func CheckCertificates() bool {
return Default.LenCertificatePair() > 0
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func GetCertificates() []tls.Certificate {
return Default.GetCertificatePair()
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func AppendCertificates(cert []tls.Certificate) []tls.Certificate {
if !CheckCertificates() {
return cert
@@ -129,67 +129,67 @@ func AppendCertificates(cert []tls.Certificate) []tls.Certificate {
return append(cert, GetCertificates()...)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func GetRootCA() *x509.CertPool {
return Default.GetRootCA()
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func GetClientCA() *x509.CertPool {
return Default.GetClientCA()
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func SetVersionMin(vers uint16) {
Default.SetVersionMin(vers)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func SetVersionMax(vers uint16) {
Default.SetVersionMax(vers)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func SetClientAuth(auth string) {
Default.SetClientAuth(StringToClientAuth(auth))
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func SetCipherList(cipher []uint16) {
Default.SetCipherList(cipher)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func SetCurve(curves []tls.CurveID) {
Default.SetCurveList(curves)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func SetDynamicSizing(enable bool) {
Default.SetDynamicSizingDisabled(!enable)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func SetSessionTicket(enable bool) {
Default.SetSessionTicketDisabled(!enable)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func GetTLSConfig(serverName string) *tls.Config {
return Default.TlsConfig(serverName)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func GetTlsConfigCertificates() *tls.Config {
return Default.TlsConfig("")
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func AddCertificateContents(keyContents, certContents string) liberr.Error {
return Default.AddCertificatePairString(keyContents, certContents)
}
// Deprecated: use local config and no more globals default config
// Deprecated: use local config and no more globals default config.
func AddCertificateFile(keyFile, certFile string) liberr.Error {
return Default.AddCertificatePairFile(keyFile, certFile)
}

View File

@@ -38,20 +38,16 @@ import (
)
type config struct {
caRoot *x509.CertPool
cert []tls.Certificate
tlsMinVersion uint16
tlsMaxVersion uint16
cipherList []uint16
curveList []tls.CurveID
dynSizingDisabled bool
ticketSessionDisabled bool
caRoot *x509.CertPool
clientAuth tls.ClientAuthType
clientCA *x509.CertPool
tlsMinVersion uint16
tlsMaxVersion uint16
dynSizingDisabled bool
ticketSessionDisabled bool
}
func (c *config) checkFile(pemFiles ...string) liberr.Error {
@@ -248,12 +244,7 @@ func (c *config) cloneCipherList() []uint16 {
return nil
}
list := make([]uint16, 0)
for _, v := range c.cipherList {
list = append(list, v)
}
return list
return append(make([]uint16, 0), c.cipherList...)
}
func (c *config) cloneCurveList() []tls.CurveID {
@@ -261,12 +252,7 @@ func (c *config) cloneCurveList() []tls.CurveID {
return nil
}
list := make([]tls.CurveID, 0)
for _, v := range c.curveList {
list = append(list, v)
}
return list
return append(make([]tls.CurveID, 0), c.curveList...)
}
func (c *config) cloneCertificates() []tls.Certificate {
@@ -274,12 +260,7 @@ func (c *config) cloneCertificates() []tls.Certificate {
return nil
}
list := make([]tls.Certificate, 0)
for _, v := range c.cert {
list = append(list, v)
}
return list
return append(make([]tls.Certificate, 0), c.cert...)
}
func (c *config) cloneRootCA() *x509.CertPool {

View File

@@ -33,12 +33,12 @@ import (
"strings"
)
// Deprecated: use StringToCipherKey
// Deprecated: use StringToCipherKey.
func GetCipherKey(cipher string) uint16 {
return StringToCipherKey(cipher)
}
// Deprecated: use StringToCurveID
// Deprecated: use StringToCurveID.
func GetCurveID(curveRef string) tls.CurveID {
return StringToCurveID(curveRef)
}

View File

@@ -223,6 +223,7 @@ func (c ConfigCluster) GetDGBConfigCluster() dgbcfg.Config {
d.Quiesce = true
}
//nolint #exhaustive
switch c.SnapshotCompressionType {
case dgbcfg.Snappy:
d.SnapshotCompressionType = dgbcfg.Snappy
@@ -230,6 +231,7 @@ func (c ConfigCluster) GetDGBConfigCluster() dgbcfg.Config {
d.SnapshotCompressionType = dgbcfg.NoCompression
}
//nolint #exhaustive
switch c.EntryCompressionType {
case dgbcfg.Snappy:
d.EntryCompressionType = dgbcfg.Snappy

View File

@@ -33,7 +33,7 @@ import (
"strconv"
"syscall"
"golang.org/x/crypto/ssh/terminal"
"golang.org/x/term"
)
func printPrompt(text string) {
@@ -87,7 +87,7 @@ func PromptBool(text string) (bool, error) {
func PromptPassword(text string) (string, error) {
printPrompt(text)
//nolint #unconvert
res, err := terminal.ReadPassword(int(syscall.Stdin))
res, err := term.ReadPassword(int(syscall.Stdin))
fmt.Printf("\n")
return string(res), err

View File

@@ -36,39 +36,43 @@ type Config interface {
Store(key string, cfg interface{})
Load(key string) interface{}
ObjectStore(key string, obj interface{})
ObjectLoad(key string) interface{}
}
func NewConfig(ctx context.Context) Config {
return &configContext{
Context: ctx,
cfg: &atomic.Value{},
obj: &atomic.Value{},
cfg: new(atomic.Value),
}
}
type configContext struct {
context.Context
cfg *atomic.Value
obj *atomic.Value
}
func (c *configContext) Store(key string, cfg interface{}) {
func (c configContext) getMap() map[string]*atomic.Value {
var (
v interface{}
s map[string]*atomic.Value
ok bool
)
if v = c.cfg.Load(); v == nil {
s = make(map[string]*atomic.Value, 0)
if c.cfg == nil {
c.cfg = new(atomic.Value)
} else if v = c.cfg.Load(); v == nil {
s = make(map[string]*atomic.Value)
} else if s, ok = v.(map[string]*atomic.Value); !ok {
s = make(map[string]*atomic.Value, 0)
s = make(map[string]*atomic.Value)
}
if _, ok = s[key]; !ok {
return s
}
func (c *configContext) Store(key string, cfg interface{}) {
s := c.getMap()
if _, ok := s[key]; !ok {
s[key] = &atomic.Value{}
}
@@ -77,17 +81,9 @@ func (c *configContext) Store(key string, cfg interface{}) {
}
func (c *configContext) Load(key string) interface{} {
var (
v interface{}
s map[string]*atomic.Value
ok bool
)
s := c.getMap()
if v = c.cfg.Load(); v == nil {
return nil
} else if s, ok = v.(map[string]*atomic.Value); !ok {
return nil
} else if _, ok = s[key]; !ok {
if _, ok := s[key]; !ok {
return nil
} else {
return s[key].Load()
@@ -97,10 +93,6 @@ func (c *configContext) Load(key string) interface{} {
func (c *configContext) Merge(cfg Config) bool {
var (
x *configContext
vx interface{}
ix interface{}
sc map[string]*atomic.Value
sx map[string]*atomic.Value
ok bool
)
@@ -108,68 +100,32 @@ func (c *configContext) Merge(cfg Config) bool {
return false
}
sc = make(map[string]*atomic.Value, 0)
s := c.getMap()
if vx = x.cfg.Load(); vx == nil {
sx = make(map[string]*atomic.Value, 0)
} else if sx, ok = vx.(map[string]*atomic.Value); !ok {
sx = make(map[string]*atomic.Value, 0)
}
for k, v := range sx {
for k, v := range x.getMap() {
if k == "" || v == nil {
continue
}
ix = v.Load()
if ix == nil {
if i := v.Load(); i == nil {
continue
} else {
s[k] = &atomic.Value{}
s[k].Store(i)
}
}
sc[k] = &atomic.Value{}
sc[k].Store(ix)
}
c.cfg.Store(sc)
c.cfg.Store(s)
return true
}
//Deprecated: use Store.
func (c *configContext) ObjectStore(key string, obj interface{}) {
var (
v interface{}
s map[string]*atomic.Value
ok bool
)
if v = c.obj.Load(); v == nil {
s = make(map[string]*atomic.Value, 0)
} else if s, ok = v.(map[string]*atomic.Value); !ok {
s = make(map[string]*atomic.Value, 0)
}
if _, ok = s[key]; !ok {
s[key] = &atomic.Value{}
}
s[key].Store(obj)
c.obj.Store(s)
c.Store(key, obj)
}
//Deprecated: use Load.
func (c *configContext) ObjectLoad(key string) interface{} {
var (
v interface{}
s map[string]*atomic.Value
ok bool
)
if v = c.obj.Load(); v == nil {
return nil
} else if s, ok = v.(map[string]*atomic.Value); !ok {
return nil
} else if _, ok = s[key]; !ok {
return nil
} else {
return s[key].Load()
}
return c.Load(key)
}

View File

@@ -27,6 +27,7 @@ package context
import "context"
func IsolateParent(parent context.Context) context.Context {
//nolint #govet
x, _ := context.WithCancel(parent)
return x
}

View File

@@ -30,9 +30,8 @@ import (
"os/signal"
"time"
"github.com/nabbar/golib/logger"
"github.com/gin-gonic/gin"
liblog "github.com/nabbar/golib/logger"
)
type GinTonic interface {
@@ -102,11 +101,11 @@ func (c *ctxGinTonic) CancelOnSignal(s ...os.Signal) {
select {
case <-sc:
logger.InfoLevel.Logf("Os Signal recieved, calling context cancel !")
liblog.InfoLevel.Logf("Os Signal received, calling context cancel !")
c.c()
return
case <-c.Done():
logger.InfoLevel.Logf("Context has been closed...")
liblog.InfoLevel.Logf("Context has been closed...")
return
}
}()

View File

@@ -91,7 +91,7 @@ type Error interface {
IsCodeError(code CodeError) bool
//HasCodeError check if current error or parent has the given error code
HasCodeError(code CodeError) bool
//GetCodeError return the CodeError value of the curent error
//GetCodeError return the CodeError value of the current error
GetCodeError() CodeError
//GetCodeErrorParent return a slice of CodeError value of all parent Error and the code of the current Error
GetCodeErrorParent() []CodeError

View File

@@ -60,7 +60,7 @@ func (r *DefaultReturn) SetError(code int, msg string, file string, line int) {
}
func (r *DefaultReturn) AddParent(code int, msg string, file string, line int) {
return
// nothing
}
func (r DefaultReturn) JSON() []byte {
@@ -89,6 +89,7 @@ func (r DefaultReturn) GinTonicErrorAbort(ctx *gin.Context, httpCode int) {
}
ctx.Errors = append(ctx.Errors, &gin.Error{
//nolint #goerr113
Err: goErr.New(r.Message),
Type: gin.ErrorTypeAny,
})

58
go.mod
View File

@@ -3,37 +3,93 @@ module github.com/nabbar/golib
go 1.16
require (
github.com/DataDog/zstd v1.4.8 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
github.com/PuerkitoBio/goquery v1.6.1 // indirect
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
github.com/VictoriaMetrics/metrics v1.17.2 // indirect
github.com/andybalholm/cascadia v1.2.0 // indirect
github.com/aokoli/goutils v1.1.1 // indirect
github.com/armon/go-metrics v0.3.6 // indirect
github.com/aws/aws-sdk-go-v2 v1.3.2
github.com/aws/aws-sdk-go-v2/config v1.1.5
github.com/aws/aws-sdk-go-v2/credentials v1.1.5
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.6 // indirect
github.com/aws/aws-sdk-go-v2/service/iam v1.3.1
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.0.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.2.2 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.5.0
github.com/aws/aws-sdk-go-v2/service/sso v1.1.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.2.2 // indirect
github.com/cockroachdb/errors v1.8.3 // indirect
github.com/cockroachdb/pebble v0.0.0-20210406003833-3d4c32f510a8 // indirect
github.com/cockroachdb/redact v1.0.9 // indirect
github.com/fatih/color v1.10.0
github.com/fxamacker/cbor/v2 v2.2.0
github.com/gin-gonic/gin v1.7.1
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
github.com/go-ldap/ldap/v3 v3.3.0
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/go-playground/validator/v10 v10.5.0
github.com/gobuffalo/envy v1.9.0 // indirect
github.com/gobuffalo/packd v1.0.0 // indirect
github.com/gobuffalo/packr v1.30.1
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.3 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/go-github/v33 v33.0.0
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.2.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-immutable-radix v1.3.0 // indirect
github.com/hashicorp/go-msgpack v1.1.5 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.6.8
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
github.com/hashicorp/go-uuid v1.0.2
github.com/hashicorp/go-version v1.3.0
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/memberlist v0.2.3 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 // indirect
github.com/json-iterator/go v1.1.10 // indirect
github.com/klauspost/compress v1.11.13 // indirect
github.com/kr/pretty v0.2.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/lni/dragonboat/v3 v3.3.2
github.com/matcornic/hermes/v2 v2.1.0
github.com/mattn/go-runewidth v0.0.12 // indirect
github.com/miekg/dns v1.1.41 // indirect
github.com/mitchellh/copystructure v1.1.2 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo v1.16.1
github.com/onsi/gomega v1.11.0
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.8.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shirou/gopsutil v3.21.3+incompatible
github.com/sirupsen/logrus v1.8.1
github.com/spf13/jwalterweatherman v1.1.0
github.com/ugorji/go v1.2.5 // indirect
github.com/vanng822/go-premailer v1.20.1 // indirect
github.com/vbauerster/mpb/v5 v5.4.0
github.com/xanzy/go-gitlab v0.48.0
github.com/xhit/go-simple-mail v2.2.2+incompatible
github.com/xujiajun/nutsdb v0.6.0
github.com/xujiajun/utils v0.0.0-20190123093513-8bf096c4f53b
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
golang.org/x/exp v0.0.0-20210405174845-4513512abef3 // indirect
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750 // indirect
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
google.golang.org/appengine v1.6.7 // indirect
)

View File

@@ -64,6 +64,7 @@ func GetClientTimeout(serverName string, http2Tr bool, GlobalTimeout time.Durati
Proxy: http.ProxyFromEnvironment,
DialContext: dl.DialContext,
DisableCompression: true,
//nolint #staticcheck
TLSClientConfig: certificates.GetTLSConfig(serverName),
}

View File

@@ -35,7 +35,6 @@ import (
"time"
"github.com/go-playground/validator/v10"
libtls "github.com/nabbar/golib/certificates"
liberr "github.com/nabbar/golib/errors"
)
@@ -129,10 +128,37 @@ func (p PoolServerConfig) MapRun(f MapRunPoolServerConfig) PoolServerConfig {
return r
}
//nolint #maligned
type ServerConfig struct {
// Name is the name of the current server
// the configuration allow multipke server, which each one must be identify by a name
// If not defined, will use the listen address
Name string `mapstructure:"name" json:"name" yaml:"name" toml:"name" validate:"required"`
// Listen is the local address (ip, hostname, unix socket, ...) with a port
// The server will bind with this address only and listen for the port defined
Listen string `mapstructure:"listen" json:"listen" yaml:"listen" toml:"listen" validate:"required,hostname_port"`
// Expose is the address use to call this server. This can be allow to use a single fqdn to multiple server"
Expose string `mapstructure:"expose" json:"expose" yaml:"expose" toml:"expose" validate:"required,url"`
// HandlerKeys is an options to associate current server with a specifc handler defined by the key
// This allow to defined multiple server in only one config for different handler to start multiple api
HandlerKeys string `mapstructure:"handler_keys" json:"handler_keys" yaml:"handler_keys" toml:"handler_keys"`
//private
getTLSDefault func() libtls.TLSConfig
//private
getParentContext func() context.Context
// TimeoutCacheInfo defined the validity time of cache for info (name, version, hash)
TimeoutCacheInfo time.Duration `mapstructure:"timeout_cache_info" json:"timeout_cache_info" yaml:"timeout_cache_info" toml:"timeout_cache_info"`
// TimeoutCacheHealth defined the validity time of cache for healthcheck of this server
TimeoutCacheHealth time.Duration `mapstructure:"timeout_cache_health" json:"timeout_cache_health" yaml:"timeout_cache_health" toml:"timeout_cache_health"`
// Enabled allow to disable a server without clean his configuration
Disabled bool `mapstructure:"disabled" json:"disabled" yaml:"disabled" toml:"disabled"`
@@ -140,11 +166,13 @@ type ServerConfig struct {
// y defined if the component for status is mandatory or not
Mandatory bool `mapstructure:"mandatory" json:"mandatory" yaml:"mandatory" toml:"mandatory"`
// TimeoutCacheInfo defined the validity time of cache for info (name, version, hash)
TimeoutCacheInfo time.Duration `mapstructure:"timeout_cache_info" json:"timeout_cache_info" yaml:"timeout_cache_info" toml:"timeout_cache_info"`
// TLSMandatory is a flag to defined that TLS must be valid to start current server.
TLSMandatory bool `mapstructure:"tls_mandatory" json:"tls_mandatory" yaml:"tls_mandatory" toml:"tls_mandatory"`
// TimeoutCacheHealth defined the validity time of cache for healthcheck of this server
TimeoutCacheHealth time.Duration `mapstructure:"timeout_cache_health" json:"timeout_cache_health" yaml:"timeout_cache_health" toml:"timeout_cache_health"`
// TLS is the tls configuration for this server.
// To allow tls on this server, at least the TLS Config option InheritDefault must be at true and the default TLS config must be set.
// If you don't want any tls config, just omit or set an empty struct.
TLS libtls.Config `mapstructure:"tls" json:"tls" yaml:"tls" toml:"tls"`
/*** http options ***/
@@ -220,30 +248,6 @@ type ServerConfig struct {
// be larger than 2^32-1. If the value is zero or larger than the
// maximum, a default value will be used instead.
MaxUploadBufferPerStream int32 `json:"max_upload_buffer_per_stream" json:"max_upload_buffer_per_stream" yaml:"max_upload_buffer_per_stream" toml:"max_upload_buffer_per_stream"`
// Name is the name of the current server
// the configuration allow multipke server, which each one must be identify by a name
// If not defined, will use the listen address
Name string `mapstructure:"name" json:"name" yaml:"name" toml:"name" validate:"required"`
// Listen is the local address (ip, hostname, unix socket, ...) with a port
// The server will bind with this address only and listen for the port defined
Listen string `mapstructure:"listen" json:"listen" yaml:"listen" toml:"listen" validate:"required,hostname_port"`
// Expose is the address use to call this server. This can be allow to use a single fqdn to multiple server"
Expose string `mapstructure:"expose" json:"expose" yaml:"expose" toml:"expose" validate:"required,url"`
// HandlerKeys is an options to associate current server with a specifc handler defined by the key
// This allow to defined multiple server in only one config for different handler to start multiple api
HandlerKeys string `mapstructure:"handler_keys" json:"handler_keys" yaml:"handler_keys" toml:"handler_keys"`
// TLSMandatory is a flag to defined that TLS must be valid to start current server.
TLSMandatory bool `mapstructure:"tls_mandatory" json:"tls_mandatory" yaml:"tls_mandatory" toml:"tls_mandatory"`
// TLS is the tls configuration for this server.
// To allow tls on this server, at least the TLS Config option InheritDefault must be at true and the default TLS config must be set.
// If you don't want any tls config, just omit or set an empty struct.
TLS libtls.Config `mapstructure:"tls" json:"tls" yaml:"tls" toml:"tls"`
}
func (c *ServerConfig) Clone() ServerConfig {
@@ -319,7 +323,7 @@ func (c ServerConfig) GetListen() *url.URL {
if c.Listen != "" {
if add, err = url.Parse(c.Listen); err != nil {
if host, prt, err := net.SplitHostPort(c.Listen); err == nil {
if host, prt, e := net.SplitHostPort(c.Listen); e == nil {
add = &url.URL{
Host: fmt.Sprintf("%s:%s", host, prt),
}

View File

@@ -36,13 +36,10 @@ import (
"strings"
"syscall"
"github.com/nabbar/golib/status"
"github.com/nabbar/golib/logger"
"github.com/nabbar/golib/semaphore"
liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger"
libsem "github.com/nabbar/golib/semaphore"
libsts "github.com/nabbar/golib/status"
)
type FieldType uint8
@@ -82,7 +79,7 @@ type PoolServer interface {
StatusInfo(bindAddress string) (name string, release string, hash string)
StatusHealth(bindAddress string) error
StatusRoute(prefix string, fctMessage status.FctMessage, sts status.RouteStatus)
StatusRoute(prefix string, fctMessage libsts.FctMessage, sts libsts.RouteStatus)
}
func NewPool(srv ...Server) PoolServer {
@@ -353,7 +350,7 @@ func (p pool) ListenMultiHandler(handler map[string]http.Handler) liberr.Error {
var e liberr.Error
e = ErrorPoolListen.Error(nil)
logger.InfoLevel.Log("Calling listen for All Servers")
liblog.InfoLevel.Log("Calling listen for All Servers")
p.MapRun(func(srv Server) {
if len(handler) < 1 {
@@ -371,7 +368,7 @@ func (p pool) ListenMultiHandler(handler map[string]http.Handler) liberr.Error {
}
})
logger.InfoLevel.Log("End of Calling listen for All Servers")
liblog.InfoLevel.Log("End of Calling listen for All Servers")
if !e.HasParent() {
e = nil
@@ -380,64 +377,66 @@ func (p pool) ListenMultiHandler(handler map[string]http.Handler) liberr.Error {
return e
}
func (p pool) Restart() {
func (p pool) runMapCommand(f func(sem libsem.Sem, srv Server)) {
if p.Len() < 1 {
return
}
var (
s semaphore.Sem
s libsem.Sem
x context.Context
c context.CancelFunc
)
x, c = context.WithTimeout(context.Background(), timeoutShutdown)
defer func() {
c()
s.DeferMain()
}()
x, c = context.WithTimeout(context.Background(), timeoutRestart)
s = semaphore.NewSemaphoreWithContext(x, 0)
s = libsem.NewSemaphoreWithContext(x, 0)
p.MapRun(func(srv Server) {
_ = s.NewWorker()
go func() {
defer s.DeferWorker()
srv.Restart()
}()
go func(sem libsem.Sem, srv Server) {
f(sem, srv)
}(s, srv)
})
_ = s.WaitAll()
}
func (p pool) runMapRestart(sem libsem.Sem, srv Server) {
defer func() {
if sem != nil {
sem.DeferWorker()
}
}()
if srv != nil {
srv.Restart()
}
}
func (p pool) runMapShutdown(sem libsem.Sem, srv Server) {
defer func() {
if sem != nil {
sem.DeferWorker()
}
}()
if srv != nil {
srv.Shutdown()
}
}
func (p pool) Restart() {
p.runMapCommand(p.runMapRestart)
}
func (p pool) Shutdown() {
if p.Len() < 1 {
return
}
var (
s semaphore.Sem
x context.Context
c context.CancelFunc
)
defer func() {
c()
s.DeferMain()
}()
x, c = context.WithTimeout(context.Background(), timeoutShutdown)
s = semaphore.NewSemaphoreWithContext(x, 0)
p.MapRun(func(srv Server) {
_ = s.NewWorker()
go func() {
defer s.DeferWorker()
srv.Shutdown()
}()
})
_ = s.WaitAll()
p.runMapCommand(p.runMapShutdown)
}
func (p pool) StatusInfo(bindAddress string) (name string, release string, hash string) {
@@ -453,10 +452,11 @@ func (p pool) StatusHealth(bindAddress string) error {
return s.StatusHealth()
}
//nolint #goerr113
return fmt.Errorf("missing server '%s'", bindAddress)
}
func (p pool) StatusRoute(keyPrefix string, fctMessage status.FctMessage, sts status.RouteStatus) {
func (p pool) StatusRoute(keyPrefix string, fctMessage libsts.FctMessage, sts libsts.RouteStatus) {
p.MapRun(func(srv Server) {
bind := srv.GetBindable()
sts.ComponentNew(fmt.Sprintf("%s-%s", keyPrefix, bind), srv.StatusComponent(fctMessage))

View File

@@ -45,6 +45,8 @@ import (
"golang.org/x/net/http2"
)
const _TimeoutWaitingPortFreeing = 500 * time.Microsecond
type srvRun struct {
err *atomic.Value
run *atomic.Value
@@ -109,6 +111,7 @@ func (s *srvRun) setErr(e error) {
if e != nil {
s.err.Store(e)
} else {
//nolint #goerr113
s.err.Store(errors.New(""))
}
}
@@ -141,6 +144,7 @@ func (s *srvRun) Merge(srv Server) bool {
panic("implement me")
}
//nolint #gocognit
func (s *srvRun) Listen(cfg *ServerConfig, handler http.Handler) liberr.Error {
ssl, err := cfg.GetTLS()
if err != nil {
@@ -263,6 +267,7 @@ func (s *srvRun) Listen(cfg *ServerConfig, handler http.Handler) liberr.Error {
s.setRunning(true)
err = s.srv.ListenAndServeTLS("", "")
} else if tlsMandatory {
//nolint #goerr113
err = fmt.Errorf("missing valid server certificates")
} else {
liblog.InfoLevel.Logf("Server '%s' is starting with bindable: %s", name, host)
@@ -333,7 +338,7 @@ func (s *srvRun) PortInUse(listen string) liberr.Error {
}
}()
ctx, cnl = context.WithTimeout(context.TODO(), 2*time.Second)
ctx, cnl = context.WithTimeout(context.TODO(), _TimeoutWaitingPortFreeing)
con, err = dia.DialContext(ctx, "tcp", listen)
if con != nil {

View File

@@ -34,24 +34,22 @@ import (
"sync/atomic"
"time"
"github.com/nabbar/golib/status"
liberr "github.com/nabbar/golib/errors"
libsts "github.com/nabbar/golib/status"
)
const (
timeoutShutdown = 10 * time.Second
timeoutRestart = 30 * time.Second
)
type server struct {
run *atomic.Value
cfg ServerConfig
cfg *atomic.Value
}
type Server interface {
GetConfig() *ServerConfig
SetConfig(cfg *ServerConfig)
SetConfig(cfg *ServerConfig) bool
GetName() string
GetBindable() string
@@ -69,16 +67,50 @@ type Server interface {
StatusInfo() (name string, release string, hash string)
StatusHealth() error
StatusComponent(message status.FctMessage) status.Component
StatusComponent(message libsts.FctMessage) libsts.Component
}
func NewServer(cfg *ServerConfig) Server {
c := new(atomic.Value)
c.Store(cfg.Clone())
return &server{
cfg: cfg.Clone(),
cfg: c,
run: new(atomic.Value),
}
}
func (s *server) GetConfig() *ServerConfig {
if s.cfg == nil {
return nil
} else if i := s.cfg.Load(); i == nil {
return nil
} else if c, ok := i.(ServerConfig); !ok {
return nil
} else {
return &c
}
}
func (s *server) SetConfig(cfg *ServerConfig) bool {
if cfg == nil {
return false
}
if s.cfg == nil {
s.cfg = new(atomic.Value)
}
c := cfg.Clone()
if c.Name == "" {
c.Name = c.GetListen().Host
}
s.cfg.Store(cfg.Clone())
return true
}
func (s *server) getRun() run {
if s.run == nil {
return newRun()
@@ -103,32 +135,20 @@ func (s *server) getErr() error {
}
}
func (s *server) GetConfig() *ServerConfig {
return &s.cfg
}
func (s *server) SetConfig(cfg *ServerConfig) {
s.cfg = cfg.Clone()
}
func (s server) GetName() string {
if s.cfg.Name == "" {
s.cfg.Name = s.GetBindable()
}
return s.cfg.Name
return s.GetConfig().Name
}
func (s *server) GetBindable() string {
return s.cfg.GetListen().Host
return s.GetConfig().GetListen().Host
}
func (s *server) GetExpose() string {
return s.cfg.GetExpose().String()
return s.GetConfig().GetExpose().String()
}
func (s *server) GetHandlerKey() string {
return s.cfg.GetHandlerKey()
return s.GetConfig().GetHandlerKey()
}
func (s *server) IsRunning() bool {
@@ -136,12 +156,12 @@ func (s *server) IsRunning() bool {
}
func (s *server) IsTLS() bool {
return s.cfg.IsTLS()
return s.GetConfig().IsTLS()
}
func (s *server) Listen(handler http.Handler) liberr.Error {
r := s.getRun()
e := r.Listen(&s.cfg, handler)
e := r.Listen(s.GetConfig(), handler)
s.setRun(r)
return e
@@ -163,12 +183,11 @@ func (s *server) Shutdown() {
}
func (s *server) Merge(srv Server) bool {
if x, ok := srv.(*server); ok {
s.cfg = x.cfg
return true
}
if x, ok := srv.(*server); !ok {
return false
} else {
return s.SetConfig(x.GetConfig())
}
}
func (s *server) StatusInfo() (name string, release string, hash string) {
@@ -180,17 +199,20 @@ func (s *server) StatusInfo() (name string, release string, hash string) {
}
func (s *server) StatusHealth() error {
if !s.cfg.Disabled && s.IsRunning() {
c := s.GetConfig()
if !c.Disabled && s.IsRunning() {
return nil
} else if s.cfg.Disabled {
} else if c.Disabled {
//nolint #goerr113
return fmt.Errorf("server disabled")
} else if e := s.getErr(); e != nil {
return e
} else {
//nolint #goerr113
return fmt.Errorf("server is offline -- missing error")
}
}
func (s *server) StatusComponent(message status.FctMessage) status.Component {
return status.NewComponent(s.cfg.Mandatory, s.StatusInfo, s.StatusHealth, message, s.cfg.TimeoutCacheInfo, s.cfg.TimeoutCacheHealth)
func (s *server) StatusComponent(message libsts.FctMessage) libsts.Component {
return libsts.NewComponent(s.GetConfig().Mandatory, s.StatusInfo, s.StatusHealth, message, s.GetConfig().TimeoutCacheInfo, s.GetConfig().TimeoutCacheHealth)
}

View File

@@ -59,8 +59,9 @@ func NewLDAP(ctx context.Context, cnf *Config, attributes []string) (*HelperLDAP
return &HelperLDAP{
Attributes: attributes,
//nolint #staticcheck
tlsConfig: libcrt.GetTLSConfig(cnf.Uri),
tlsMode: tlsmode_init,
tlsMode: _TLSModeInit,
config: cnf.Clone(),
ctx: libctx.IsolateParent(ctx),
}, nil
@@ -83,15 +84,15 @@ func (lc *HelperLDAP) ForceTLSMode(tlsMode TLSMode, tlsConfig *tls.Config) {
}
switch tlsMode {
case TLSMODE_TLS:
lc.tlsMode = TLSMODE_TLS
case TLSMODE_STARTTLS:
lc.tlsMode = TLSMODE_STARTTLS
case TLSMODE_NONE:
case TLSModeTLS:
lc.tlsMode = TLSModeTLS
case TLSModeStarttls:
lc.tlsMode = TLSModeStarttls
case TLSModeNone:
lc.tlsConfig = nil
lc.tlsMode = TLSMODE_NONE
case tlsmode_init:
lc.tlsMode = tlsmode_init
lc.tlsMode = TLSModeNone
case _TLSModeInit:
lc.tlsMode = _TLSModeInit
}
}
@@ -175,7 +176,7 @@ func (lc *HelperLDAP) starttls(l *ldap.Conn) liberr.Error {
func (lc *HelperLDAP) tryConnect() (TLSMode, liberr.Error) {
if lc == nil {
return TLSMODE_NONE, ErrorEmptyParams.Error(nil)
return TLSModeNone, ErrorEmptyParams.Error(nil)
}
var (
@@ -192,32 +193,32 @@ func (lc *HelperLDAP) tryConnect() (TLSMode, liberr.Error) {
if lc.config.Portldaps != 0 {
l, err = lc.dialTLS()
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSMODE_TLS.String())
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSModeTLS.String())
if err == nil {
return TLSMODE_TLS, nil
return TLSModeTLS, nil
}
}
if lc.config.PortLdap == 0 {
return tlsmode_init, ErrorLDAPServerConfig.Error(nil)
return _TLSModeInit, ErrorLDAPServerConfig.Error(nil)
}
l, err = lc.dial()
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSMODE_NONE.String())
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSModeNone.String())
if err != nil {
return tlsmode_init, err
return _TLSModeInit, err
}
err = lc.starttls(l)
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSMODE_STARTTLS.String())
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSModeStarttls.String())
if err == nil {
return TLSMODE_STARTTLS, nil
return TLSModeStarttls, nil
}
return TLSMODE_NONE, nil
return TLSModeNone, nil
}
func (lc *HelperLDAP) connect() liberr.Error {
@@ -235,7 +236,7 @@ func (lc *HelperLDAP) connect() liberr.Error {
err liberr.Error
)
if lc.tlsMode == tlsmode_init {
if lc.tlsMode == _TLSModeInit {
m, e := lc.tryConnect()
if e != nil {
@@ -245,7 +246,7 @@ func (lc *HelperLDAP) connect() liberr.Error {
lc.tlsMode = m
}
if lc.tlsMode == TLSMODE_TLS {
if lc.tlsMode == TLSModeTLS {
l, err = lc.dialTLS()
if err != nil {
if l != nil {
@@ -255,7 +256,7 @@ func (lc *HelperLDAP) connect() liberr.Error {
}
}
if lc.tlsMode == TLSMODE_NONE || lc.tlsMode == TLSMODE_STARTTLS {
if lc.tlsMode == TLSModeNone || lc.tlsMode == TLSModeStarttls {
l, err = lc.dial()
if err != nil {
if l != nil {
@@ -265,7 +266,7 @@ func (lc *HelperLDAP) connect() liberr.Error {
}
}
if lc.tlsMode == TLSMODE_STARTTLS {
if lc.tlsMode == TLSModeStarttls {
err = lc.starttls(l)
if err != nil {
if l != nil {
@@ -346,7 +347,7 @@ func (lc *HelperLDAP) Connect() liberr.Error {
return err
}
liblog.DebugLevel.Logf("Bind success on LDAP server %s with tls mode '%s'", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String())
liblog.DebugLevel.Logf("Bind success on LDAP server %s with tls mode '%s'", lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String())
return nil
}
@@ -376,7 +377,7 @@ func (lc *HelperLDAP) runSearch(filter string, attributes []string) (*ldap.Searc
return nil, ErrorLDAPSearch.ErrorParent(err)
}
liblog.DebugLevel.Logf("Search success on server '%s' with tls mode '%s', with filter [%s] and attribute %v", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), filter, attributes)
liblog.DebugLevel.Logf("Search success on server '%s' with tls mode '%s', with filter [%s] and attribute %v", lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), filter, attributes)
return src, nil
}
@@ -405,46 +406,10 @@ func (lc *HelperLDAP) getUserName(username string) (string, liberr.Error) {
//UserInfo used to retrieve the information of a given username.
func (lc *HelperLDAP) UserInfo(username string) (map[string]string, liberr.Error) {
var (
err liberr.Error
src *ldap.SearchResult
userRes map[string]string
)
if username, err = lc.getUserName(username); err != nil {
return nil, err
return lc.UserInfoByField(username, userFieldUid)
}
userRes = make(map[string]string)
attributes := append(lc.Attributes, "cn")
src, err = lc.runSearch(fmt.Sprintf(lc.config.FilterUser, userFieldUid, username), attributes)
if err != nil {
return userRes, err
}
if len(src.Entries) != 1 {
if len(src.Entries) > 1 {
return userRes, ErrorLDAPUserNotUniq.Error(nil)
} else {
return userRes, ErrorLDAPUserNotFound.Error(nil)
}
}
for _, attr := range attributes {
userRes[attr] = src.Entries[0].GetAttributeValue(attr)
}
if _, ok := userRes["DN"]; !ok {
userRes["DN"] = src.Entries[0].DN
}
liblog.DebugLevel.Logf("Map info retrieve in ldap server '%s' with tls mode '%s' about user [%s] : %v", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), username, userRes)
return userRes, nil
}
//UserInfo used to retrieve the information of a given username.
//UserInfoByField used to retrieve the information of a given username but use a given field to make the search.
func (lc *HelperLDAP) UserInfoByField(username string, fieldOfUnicValue string) (map[string]string, liberr.Error) {
var (
err liberr.Error
@@ -481,39 +446,16 @@ func (lc *HelperLDAP) UserInfoByField(username string, fieldOfUnicValue string)
userRes["DN"] = src.Entries[0].DN
}
liblog.DebugLevel.Logf("Map info retrieve in ldap server '%s' with tls mode '%s' about user [%s] : %v", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), username, userRes)
liblog.DebugLevel.Logf("Map info retrieve in ldap server '%s' with tls mode '%s' about user [%s] : %v", lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), username, userRes)
return userRes, nil
}
//GroupInfo used to retrieve the information of a given group cn.
func (lc *HelperLDAP) GroupInfo(groupname string) (map[string]interface{}, liberr.Error) {
var (
err liberr.Error
src *ldap.SearchResult
grpInfo map[string]interface{}
)
src, err = lc.runSearch(fmt.Sprintf(lc.config.FilterGroup, groupFieldCN, groupname), []string{})
if err != nil {
return grpInfo, err
return lc.GroupInfoByField(groupname, groupFieldCN)
}
if len(src.Entries) == 0 {
return nil, ErrorLDAPGroupNotFound.Error(nil)
}
grpInfo = make(map[string]interface{}, len(src.Entries[0].Attributes))
for _, entry := range src.Entries {
for _, entryAttribute := range entry.Attributes {
grpInfo[entryAttribute.Name] = entryAttribute.Values
}
}
liblog.DebugLevel.Logf("Info for group [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grpInfo)
return grpInfo, nil
}
//GroupInfo used to retrieve the information of a given group cn.
//GroupInfoByField used to retrieve the information of a given group cn, but use a given field to make the search.
func (lc *HelperLDAP) GroupInfoByField(groupname string, fieldForUnicValue string) (map[string]interface{}, liberr.Error) {
var (
err liberr.Error
@@ -537,7 +479,7 @@ func (lc *HelperLDAP) GroupInfoByField(groupname string, fieldForUnicValue strin
}
}
liblog.DebugLevel.Logf("Info for group [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grpInfo)
liblog.DebugLevel.Logf("Info for group [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), grpInfo)
return grpInfo, nil
}
@@ -562,13 +504,13 @@ func (lc *HelperLDAP) UserMemberOf(username string) ([]string, liberr.Error) {
for _, entry := range src.Entries {
for _, mmb := range entry.GetAttributeValues("memberOf") {
liblog.DebugLevel.Logf("Group find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), mmb)
liblog.DebugLevel.Logf("Group find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), mmb)
mmo := lc.ParseEntries(mmb)
grp = append(grp, mmo["cn"]...)
}
}
liblog.DebugLevel.Logf("Groups find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grp)
liblog.DebugLevel.Logf("Groups find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), grp)
return grp, nil
}
@@ -618,7 +560,7 @@ func (lc *HelperLDAP) UsersOfGroup(groupname string) ([]string, liberr.Error) {
}
}
liblog.DebugLevel.Logf("Member of groups [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grp)
liblog.DebugLevel.Logf("Member of groups [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), grp)
return grp, nil
}

View File

@@ -35,13 +35,13 @@ import (
type TLSMode uint8
const (
tlsmode_init TLSMode = iota
_TLSModeInit TLSMode = iota
//TLSModeNone no tls connection.
TLSMODE_NONE TLSMode = iota + 1
TLSModeNone TLSMode = iota + 1
//TLSModeTLS strict tls connection.
TLSMODE_TLS
//TLSModeStartTLS starttls connection (tls into a no tls connection).
TLSMODE_STARTTLS
TLSModeTLS
//TLSModeStarttls starttls connection (tls into a no tls connection).
TLSModeStarttls
)
const (
@@ -51,17 +51,17 @@ const (
func (m TLSMode) String() string {
switch m {
case TLSMODE_STARTTLS:
case TLSModeStarttls:
return "starttls"
case TLSMODE_TLS:
case TLSModeTLS:
return "tls"
case TLSMODE_NONE:
case TLSModeNone:
return "none"
case tlsmode_init:
case _TLSModeInit:
return "not defined"
}
return tlsmode_init.String()
return _TLSModeInit.String()
}
func GetDefaultAttributes() []string {
@@ -123,6 +123,7 @@ func (cnf Config) Validate() errors.Error {
}
for _, err := range err.(validator.ValidationErrors) {
//nolint #goerr113
e.AddParent(fmt.Errorf("config field '%s' is not validated by constraint '%s'", err.StructNamespace(), err.ActualTag()))
}
}

View File

@@ -1,66 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package mail
import "io"
const maxLineChars = 76
type base64LineWrap struct {
writer io.Writer
numLineChars int
}
func (e *base64LineWrap) Write(p []byte) (n int, err error) {
n = 0
// while we have more chars than are allowed
for len(p)+e.numLineChars > maxLineChars {
numCharsToWrite := maxLineChars - e.numLineChars
// write the chars we can
/* #nosec */
//nolint #nosec
_, _ = e.writer.Write(p[:numCharsToWrite])
// write a line break
/* #nosec */
//nolint #nosec
_, _ = e.writer.Write([]byte("\r\n"))
// reset the line count
e.numLineChars = 0
// remove the chars that have been written
p = p[numCharsToWrite:]
// set the num of chars written
n += numCharsToWrite
}
// write what is left
/* #nosec */
//nolint #nosec
_, _ = e.writer.Write(p)
e.numLineChars += len(p)
n += len(p)
return
}

View File

@@ -28,9 +28,9 @@ package mail
type ContentType uint8
const (
// TextPlain sets body type to text/plain in message body
// ContentPlainText sets body type to text/plain in message body.
ContentPlainText ContentType = iota
// TextHTML sets body type to text/html in message body
// ContentHTML sets body type to text/html in message body.
ContentHTML
)
@@ -44,14 +44,3 @@ func (c ContentType) String() string {
return ContentPlainText.String()
}
func (c ContentType) getContentType() string {
switch c {
case ContentPlainText:
return "text/plain"
case ContentHTML:
return "text/html"
}
return ContentPlainText.getContentType()
}

View File

@@ -1,200 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package mail
import (
"bufio"
"bytes"
"fmt"
"io"
"strings"
"unicode/utf8"
)
type encoder struct {
w *bufio.Writer
charset string
usedChars int
}
// newEncoder returns a new mime header encoder that writes to w. The c
// parameter specifies the name of the character set of the text that will be
// encoded. The u parameter indicates how many characters have been used
// already.
func newEncoder(w io.Writer, c string, u int) *encoder {
return &encoder{bufio.NewWriter(w), strings.ToUpper(c), u}
}
// encode encodes p using the "Q" encoding and writes it to the underlying
// io.Writer. It limits line length to 75 characters.
func (e *encoder) encode(p []byte) (n int, err error) {
var output bytes.Buffer
allPrintable := true
// some lines we encode end in "
//maxLineLength := 75 - 1
maxLineLength := 76
// prevent header injection
p = e.secureHeader(p)
// check to see if we have all printable characters
for _, c := range p {
if !e.isVchar(c) && !e.isWSP(c) {
allPrintable = false
break
}
}
// all characters are printable. just do line folding
if allPrintable {
text := string(p)
words := strings.Split(text, " ")
lineBuffer := ""
firstWord := true
// split the line where necessary
for _, word := range words {
newWord := ""
if !firstWord {
newWord += " "
}
newWord += word
// check line length
if (e.usedChars+len(lineBuffer)+len(newWord) /*+len(" ")+len(word)*/) > maxLineLength && (lineBuffer != "" || e.usedChars != 0) {
output.WriteString(lineBuffer + "\r\n")
// first word on newline needs a space in front
if !firstWord {
lineBuffer = ""
} else {
lineBuffer = " "
}
// reset since not on the first line anymore
e.usedChars = 0
}
lineBuffer += newWord /*word*/
firstWord = false
}
output.WriteString(lineBuffer)
} else {
firstLine := true
// A single encoded word can not be longer than 75 characters
if e.usedChars == 0 {
maxLineLength = 75
}
wordBegin := "=?" + e.charset + "?Q?"
wordEnd := "?="
lineBuffer := wordBegin
for i := 0; i < len(p); {
// encode the character
encodedChar, runeLength := e.encodeChar(p, i)
// Check line length
if len(lineBuffer)+e.usedChars+len(encodedChar) > (maxLineLength - len(wordEnd)) {
output.WriteString(lineBuffer + wordEnd + "\r\n")
lineBuffer = " " + wordBegin
firstLine = false
}
lineBuffer += encodedChar
i = i + runeLength
// reset since not on the first line anymore
if !firstLine {
e.usedChars = 0
maxLineLength = 76
}
}
output.WriteString(lineBuffer + wordEnd)
}
_, _ = e.w.Write(output.Bytes())
_ = e.w.Flush()
n = output.Len()
return n, nil
}
// encode takes a string and position in that string and encodes one utf-8
// character. It then returns the encoded string and number of runes in the
// character.
func (e *encoder) encodeChar(text []byte, i int) (encodedString string, runeLength int) {
started := false
for ; i < len(text) && (!utf8.RuneStart(text[i]) || !started); i++ {
switch c := text[i]; {
case c == ' ':
encodedString += "_"
case e.isVchar(c) && c != '=' && c != '?' && c != '_':
encodedString += string(c)
default:
encodedString += fmt.Sprintf("=%02X", c)
}
runeLength++
started = true
}
return
}
// secureHeader removes all unnecessary values to prevent
// header injection
func (e *encoder) secureHeader(text []byte) []byte {
secureValue := strings.TrimSpace(string(text))
secureValue = strings.Replace(secureValue, "\r", "", -1)
secureValue = strings.Replace(secureValue, "\n", "", -1)
secureValue = strings.Replace(secureValue, "\t", "", -1)
return []byte(secureValue)
}
// isVchar returns true if c is an RFC 5322 VCHAR character.
func (e *encoder) isVchar(c byte) bool {
// Visible (printing) characters.
return '!' <= c && c <= '~'
}
// isWSP returns true if c is a WSP (white space).
// WSP is a space or horizontal tab (RFC5234 Appendix B).
func (e *encoder) isWSP(c byte) bool {
return c == ' ' || c == '\t'
}

View File

@@ -28,16 +28,16 @@ package mail
type Encoding uint8
const (
// EncodingNone turns off encoding on the message body
// EncodingNone turns off encoding on the message body.
EncodingNone Encoding = iota
// EncodingBinary is equal to EncodingNone, but string is set to binrary instead of none
// EncodingBinary is equal to EncodingNone, but string is set to binary instead of none.
EncodingBinary
// EncodingBase64 sets the message body encoding to base64
// EncodingBase64 sets the message body encoding to base64.
EncodingBase64
// EncodingQuotedPrintable sets the message body encoding to quoted-printable
// EncodingQuotedPrintable sets the message body encoding to quoted-printable.
EncodingQuotedPrintable
)
@@ -54,16 +54,3 @@ func (e Encoding) String() string {
}
return EncodingNone.String()
}
func (e Encoding) getEncoding() string {
switch e {
case EncodingNone, EncodingBinary:
return "binary"
case EncodingBase64:
return "base64"
case EncodingQuotedPrintable:
return "quoted-printable"
}
return EncodingNone.getEncoding()
}

View File

@@ -36,7 +36,7 @@ import (
)
const (
MailDateTimeLayout = time.RFC1123Z
DateTimeLayout = time.RFC1123Z
headerMimeVersion = "MIME-Version"
headerDate = "Date"
@@ -44,17 +44,16 @@ const (
)
type mail struct {
headers textproto.MIMEHeader
charset string
encoding Encoding
date time.Time
subject string
priority Priority
address *email
attach []File
inline []File
body []Body
charset string
subject string
headers textproto.MIMEHeader
address *email
encoding Encoding
priority Priority
}
func (m *mail) Email() Email {
@@ -112,7 +111,7 @@ func (m *mail) SetDateString(layout, datetime string) liberr.Error {
}
func (m *mail) GetDateString() string {
return m.date.Format(MailDateTimeLayout)
return m.date.Format(DateTimeLayout)
}
func (m *mail) AddHeader(key string, values ...string) {
@@ -182,7 +181,7 @@ func (m *mail) GetHeaders() textproto.MIMEHeader {
h = m.addHeader(h, key, values...)
})
for k, _ := range m.headers {
for k := range m.headers {
h = m.addHeader(h, k, m.headers.Values(k)...)
}

View File

@@ -34,11 +34,11 @@ const (
type Priority uint8
const (
// PriorityNormal sets the email priority to normal
// PriorityNormal sets the email priority to normal.
PriorityNormal Priority = iota
// PriorityLow sets the email priority to Low
// PriorityLow sets the email priority to Low.
PriorityLow
// PriorityHigh sets the email priority to High
// PriorityHigh sets the email priority to High.
PriorityHigh
)
@@ -71,9 +71,9 @@ func (p Priority) headerPriority() string {
func (p Priority) headerImportance() string {
switch p {
case PriorityLow:
return "Low"
return PriorityLow.String()
case PriorityHigh:
return "High"
return PriorityHigh.String()
case PriorityNormal:
return ""
}
@@ -84,9 +84,9 @@ func (p Priority) headerImportance() string {
func (p Priority) headerMSMailPriority() string {
switch p {
case PriorityLow:
return "Low"
return PriorityLow.String()
case PriorityHigh:
return "High"
return PriorityHigh.String()
case PriorityNormal:
return ""
}

View File

@@ -31,29 +31,32 @@ import (
"fmt"
"io"
"github.com/nabbar/golib/smtp"
"github.com/nabbar/golib/ioutils"
liberr "github.com/nabbar/golib/errors"
libiot "github.com/nabbar/golib/ioutils"
libsmtp "github.com/nabbar/golib/smtp"
simple "github.com/xhit/go-simple-mail"
)
const (
_MinSizeAddr = 4
)
type Sender interface {
Close() error
Send(ctx context.Context, cli smtp.SMTP) liberr.Error
SendClose(ctx context.Context, cli smtp.SMTP) liberr.Error
Send(ctx context.Context, cli libsmtp.SMTP) liberr.Error
SendClose(ctx context.Context, cli libsmtp.SMTP) liberr.Error
}
type sender struct {
data ioutils.FileProgress
data libiot.FileProgress
from string
rcpt []string
}
//nolint #gocognit
func (m *mail) Sender() (snd Sender, err liberr.Error) {
e := simple.NewMSG()
f := make([]ioutils.FileProgress, 0)
f := make([]libiot.FileProgress, 0)
switch m.GetPriority() {
case PriorityHigh:
@@ -142,7 +145,7 @@ func (m *mail) Sender() (snd Sender, err liberr.Error) {
if len(m.attach) > 0 {
for _, i := range m.attach {
if t, er := ioutils.NewFileProgressTemp(); er != nil {
if t, er := libiot.NewFileProgressTemp(); er != nil {
return nil, er
} else if _, er := t.ReadFrom(i.data); er != nil {
return nil, ErrorIORead.ErrorParent(er)
@@ -156,7 +159,7 @@ func (m *mail) Sender() (snd Sender, err liberr.Error) {
if len(m.inline) > 0 {
for _, i := range m.inline {
if t, er := ioutils.NewFileProgressTemp(); er != nil {
if t, er := libiot.NewFileProgressTemp(); er != nil {
return nil, er
} else if _, er := t.ReadFrom(i.data); er != nil {
return nil, ErrorIORead.ErrorParent(er)
@@ -206,7 +209,7 @@ func (m *mail) Sender() (snd Sender, err liberr.Error) {
s.rcpt = append(s.rcpt, m.Email().GetRecipients(RecipientCC)...)
s.rcpt = append(s.rcpt, m.Email().GetRecipients(RecipientBCC)...)
if tmp, err := ioutils.NewFileProgressTemp(); err != nil {
if tmp, err := libiot.NewFileProgressTemp(); err != nil {
return nil, err
} else if _, er := tmp.WriteString(e.GetMessage()); er != nil {
return nil, ErrorIOWrite.ErrorParent(er)
@@ -222,7 +225,7 @@ func (m *mail) Sender() (snd Sender, err liberr.Error) {
return
}
func (s *sender) SendClose(ctx context.Context, cli smtp.SMTP) liberr.Error {
func (s *sender) SendClose(ctx context.Context, cli libsmtp.SMTP) liberr.Error {
defer func() {
_ = s.Close()
}()
@@ -234,14 +237,16 @@ func (s *sender) SendClose(ctx context.Context, cli smtp.SMTP) liberr.Error {
return nil
}
func (s *sender) Send(ctx context.Context, cli smtp.SMTP) liberr.Error {
func (s *sender) Send(ctx context.Context, cli libsmtp.SMTP) liberr.Error {
if e := cli.Check(ctx); e != nil {
return ErrorSmtpClient.ErrorParent(e)
}
if len(s.from) < 4 {
if len(s.from) < _MinSizeAddr {
//nolint #goerr113
return ErrorParamsEmpty.ErrorParent(fmt.Errorf("parameters 'from' is not valid"))
} else if len(s.rcpt) < 1 || len(s.rcpt[0]) < 4 {
} else if len(s.rcpt) < 1 || len(s.rcpt[0]) < _MinSizeAddr {
//nolint #goerr113
return ErrorParamsEmpty.ErrorParent(fmt.Errorf("parameters 'receipient' is not valid"))
}

View File

@@ -1,83 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package mail
import (
"bytes"
"encoding/base64"
"mime/quotedprintable"
"strings"
)
// base64Encode base64 encodes the provided text with line wrapping
func base64Encode(text []byte) []byte {
// create buffer
buf := new(bytes.Buffer)
// create base64 encoder that linewraps
encoder := base64.NewEncoder(base64.StdEncoding, &base64LineWrap{writer: buf})
// write the encoded text to buf
/* #nosec */
//nolint #nosec
_, _ = encoder.Write(text)
_ = encoder.Close()
return buf.Bytes()
}
// qpEncode uses the quoted-printable encoding to encode the provided text
func qpEncode(text []byte) []byte {
// create buffer
buf := new(bytes.Buffer)
encoder := quotedprintable.NewWriter(buf)
/* #nosec */
//nolint #nosec
_, _ = encoder.Write(text)
_ = encoder.Close()
return buf.Bytes()
}
func encodeHeader(text string, charset string, usedChars int) string {
// create buffer
buf := new(bytes.Buffer)
// encode
encoder := newEncoder(buf, charset, usedChars)
/* #nosec */
//nolint #nosec
_, _ = encoder.encode([]byte(text))
return buf.String()
}
func escapeQuotes(s string) string {
quoteEscaper := strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
return quoteEscaper.Replace(s)
}

View File

@@ -28,10 +28,10 @@ package mailer
import "github.com/matcornic/hermes/v2"
type email struct {
t Themes
d TextDirection
p hermes.Product
b *hermes.Body
t Themes
d TextDirection
c bool
}

View File

@@ -33,27 +33,14 @@ import (
)
func (e *email) GenerateHTML() (*bytes.Buffer, liberr.Error) {
var buf = bytes.NewBuffer(make([]byte, 0))
h := hermes.Hermes{
Theme: e.t.getHermes(),
TextDirection: e.d.getDirection(),
Product: e.p,
DisableCSSInlining: e.c,
}
if p, e := h.GenerateHTML(hermes.Email{
Body: *e.b,
}); e != nil {
return nil, ErrorMailerHtml.ErrorParent(e)
} else {
buf.WriteString(p)
}
return buf, nil
return e.generated(e.genHtml)
}
func (e *email) GeneratePlainText() (*bytes.Buffer, liberr.Error) {
return e.generated(e.genText)
}
func (e email) generated(f func(h hermes.Hermes, m hermes.Email) (string, error)) (*bytes.Buffer, liberr.Error) {
var buf = bytes.NewBuffer(make([]byte, 0))
h := hermes.Hermes{
@@ -63,7 +50,7 @@ func (e *email) GeneratePlainText() (*bytes.Buffer, liberr.Error) {
DisableCSSInlining: e.c,
}
if p, e := h.GeneratePlainText(hermes.Email{
if p, e := f(h, hermes.Email{
Body: *e.b,
}); e != nil {
return nil, ErrorMailerText.ErrorParent(e)
@@ -73,3 +60,11 @@ func (e *email) GeneratePlainText() (*bytes.Buffer, liberr.Error) {
return buf, nil
}
func (e *email) genText(h hermes.Hermes, m hermes.Email) (string, error) {
return h.GeneratePlainText(m)
}
func (e *email) genHtml(h hermes.Hermes, m hermes.Email) (string, error) {
return h.GenerateHTML(m)
}

View File

@@ -66,6 +66,7 @@ func (o NutsDBOptions) GetNutsDBOptions(dataDir string) nutsdb.Options {
} else {
d.Dir = dataDir
//nolint #exhaustive
switch o.RWMode {
case nutsdb.MMap:
d.RWMode = nutsdb.MMap
@@ -73,6 +74,7 @@ func (o NutsDBOptions) GetNutsDBOptions(dataDir string) nutsdb.Options {
d.RWMode = nutsdb.FileIO
}
//nolint #exhaustive
switch o.StartFileLoadingMode {
case nutsdb.MMap:
d.StartFileLoadingMode = nutsdb.MMap
@@ -81,6 +83,7 @@ func (o NutsDBOptions) GetNutsDBOptions(dataDir string) nutsdb.Options {
}
}
//nolint #exhaustive
switch o.EntryIdxMode {
case nutsdb.HintKeyAndRAMIdxMode:
d.EntryIdxMode = nutsdb.HintKeyAndRAMIdxMode

View File

@@ -104,7 +104,7 @@ func (s *snap) Save(opt Options, writer io.Writer) liberr.Error {
_ = t.Close()
}()
if _, e = archive.CreateArchive(archive.ArchiveTypeTarGzip, t, s.path); e != nil {
if _, e = archive.CreateArchive(archive.TypeTarGzip, t, s.path); e != nil {
return ErrorFolderArchive.Error(e)
}

View File

@@ -29,12 +29,30 @@ import (
"github.com/gin-gonic/gin"
)
const EMPTY_GROUP = "<nil>"
const EmptyHandlerGroup = "<nil>"
var (
defaultRouters = NewRouterList()
defaultRouters = NewRouterList(DefaultGinInit)
)
func DefaultGinInit() *gin.Engine {
engine := gin.New()
engine.Use(gin.Logger(), gin.Recovery())
return engine
}
func DefaultGinWithTrustyProxy(trustyProxy []string) *gin.Engine {
engine := gin.New()
engine.Use(gin.Logger(), gin.Recovery())
if len(trustyProxy) > 0 {
engine.TrustedProxies = trustyProxy
}
return engine
}
type routerItem struct {
method string
relative string
@@ -42,6 +60,7 @@ type routerItem struct {
}
type routerList struct {
init func() *gin.Engine
list map[string][]routerItem
}
@@ -52,6 +71,7 @@ type RouterList interface {
Register(method string, relativePath string, router ...gin.HandlerFunc)
RegisterInGroup(group, method string, relativePath string, router ...gin.HandlerFunc)
Handler(engine *gin.Engine)
Engine() *gin.Engine
}
func RoutersRegister(method string, relativePath string, router ...gin.HandlerFunc) {
@@ -66,15 +86,16 @@ func RoutersHandler(engine *gin.Engine) {
defaultRouters.Handler(engine)
}
func NewRouterList() RouterList {
func NewRouterList(initGin func() *gin.Engine) RouterList {
return &routerList{
init: initGin,
list: make(map[string][]routerItem),
}
}
func (l routerList) Handler(engine *gin.Engine) {
for grpRoute, grpList := range l.list {
if grpRoute == EMPTY_GROUP {
if grpRoute == EmptyHandlerGroup {
for _, r := range grpList {
engine.Handle(r.method, r.relative, r.router...)
}
@@ -89,7 +110,7 @@ func (l routerList) Handler(engine *gin.Engine) {
func (l *routerList) RegisterInGroup(group, method string, relativePath string, router ...gin.HandlerFunc) {
if group == "" {
group = EMPTY_GROUP
group = EmptyHandlerGroup
}
if _, ok := l.list[group]; !ok {
@@ -106,3 +127,11 @@ func (l *routerList) RegisterInGroup(group, method string, relativePath string,
func (l *routerList) Register(method string, relativePath string, router ...gin.HandlerFunc) {
l.RegisterInGroup("", method, relativePath, router...)
}
func (l routerList) Engine() *gin.Engine {
if l.init != nil {
return l.init()
} else {
return DefaultGinInit()
}
}

View File

@@ -44,14 +44,13 @@ func SetGinHandler(fct func(c *gin.Context)) gin.HandlerFunc {
}
func Handler(routerList RouterList) http.Handler {
engine := gin.New()
engine.Use(gin.Logger(), gin.Recovery())
e := routerList.Engine()
if routerList == nil {
RoutersHandler(engine)
RoutersHandler(e)
} else {
routerList.Handler(engine)
routerList.Handler(e)
}
return engine
return e
}

View File

@@ -70,17 +70,6 @@ func (s *smtpClient) dial(ctx context.Context, addr string) (con net.Conn, err l
return
}
func (s *smtpClient) dialStarttls(ctx context.Context, addr string, tlsConfig *tls.Config) (con net.Conn, err liberr.Error) {
defer func() {
if err != nil && con != nil {
_ = con.Close()
}
}()
con, err = s.dial(ctx, addr)
return
}
func (s *smtpClient) client(ctx context.Context, addr string, tlsConfig *tls.Config) (cli *smtp.Client, con net.Conn, err liberr.Error) {
var e error

View File

@@ -120,7 +120,7 @@ func (s *smtpClient) Client(ctx context.Context) (*smtp.Client, errors.Error) {
return s.cli, nil
}
// validateLine checks to see if a line has CR or LF as per RFC 5321
// validateLine checks to see if a line has CR or LF as per RFC 5321.
func (s smtpClient) validateLine(line string) errors.Error {
if strings.ContainsAny(line, "\n\r") {
return ErrorSMTPLineCRLF.Error(nil)

View File

@@ -29,10 +29,9 @@ import (
"net/http"
"sync/atomic"
"github.com/nabbar/golib/version"
"github.com/gin-gonic/gin"
"github.com/nabbar/golib/router"
librtr "github.com/nabbar/golib/router"
libver "github.com/nabbar/golib/version"
)
const statusOK = "OK"
@@ -82,8 +81,8 @@ type RouteStatus interface {
HttpStatusCode(codeOk, codeKO, codeWarning int)
Get(c *gin.Context)
Register(prefix string, register router.RegisterRouter)
RegisterGroup(group, prefix string, register router.RegisterRouterInGroup)
Register(prefix string, register librtr.RegisterRouter)
RegisterGroup(group, prefix string, register librtr.RegisterRouterInGroup)
ComponentNew(key string, cpt Component)
ComponentDel(key string)
@@ -102,10 +101,10 @@ func New(Name string, Release string, Hash string, msgOk string, msgKo string, m
cKO: http.StatusServiceUnavailable,
mWM: msgWarm,
cWM: http.StatusOK,
c: make(map[string]*atomic.Value, 0),
c: make(map[string]*atomic.Value),
}
}
func NewVersion(version version.Version, msgOk string, msgKO string, msgWarm string) RouteStatus {
func NewVersion(version libver.Version, msgOk string, msgKO string, msgWarm string) RouteStatus {
return New(version.GetPackage(), version.GetRelease(), version.GetBuild(), msgOk, msgKO, msgWarm)
}

View File

@@ -31,12 +31,11 @@ import (
"strings"
"sync/atomic"
"github.com/gin-gonic/gin"
liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger"
"github.com/gin-gonic/gin"
"github.com/nabbar/golib/router"
"github.com/nabbar/golib/semaphore"
librtr "github.com/nabbar/golib/router"
libsem "github.com/nabbar/golib/semaphore"
)
type rtrStatus struct {
@@ -74,7 +73,7 @@ func (r *rtrStatus) cleanPrefix(prefix string) string {
return path.Clean(strings.TrimRight(path.Join("/", prefix), "/"))
}
func (r *rtrStatus) Register(prefix string, register router.RegisterRouter) {
func (r *rtrStatus) Register(prefix string, register librtr.RegisterRouter) {
prefix = r.cleanPrefix(prefix)
var m = r.m
@@ -86,7 +85,7 @@ func (r *rtrStatus) Register(prefix string, register router.RegisterRouter) {
}
}
func (r *rtrStatus) RegisterGroup(group, prefix string, register router.RegisterRouterInGroup) {
func (r *rtrStatus) RegisterGroup(group, prefix string, register librtr.RegisterRouterInGroup) {
prefix = r.cleanPrefix(prefix)
var m = r.m
@@ -107,7 +106,7 @@ func (r *rtrStatus) Get(x *gin.Context) {
key string
err liberr.Error
rsp *Response
sem semaphore.Sem
sem libsem.Sem
)
defer func() {
@@ -130,7 +129,7 @@ func (r *rtrStatus) Get(x *gin.Context) {
Components: make([]CptResponse, 0),
}
sem = semaphore.NewSemaphoreWithContext(x, 0)
sem = libsem.NewSemaphoreWithContext(x, 0)
for key, atm = range r.c {
if atm == nil {
@@ -182,7 +181,7 @@ func (r *rtrStatus) Get(x *gin.Context) {
func (r *rtrStatus) ComponentNew(key string, cpt Component) {
if len(r.c) < 1 {
r.c = make(map[string]*atomic.Value, 0)
r.c = make(map[string]*atomic.Value)
}
if _, ok := r.c[key]; !ok {

View File

@@ -75,6 +75,8 @@ func main() {
}
}
//nolint #gosec
/* #nosec */
if file, err := os.OpenFile(LoggerFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666); err != nil {
panic(err)
} else {