view pkg/common/random.go @ 5490:5f47eeea988d logging

Use own logging package.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 20 Sep 2021 17:45:39 +0200
parents 8c5df0f3562e
children
line wrap: on
line source

// This is Free Software under GNU Affero General Public License v >= 3.0
// without warranty, see README.md and license for details.
//
// SPDX-License-Identifier: AGPL-3.0-or-later
// License-Filename: LICENSES/AGPL-3.0.txt
//
// Copyright (C) 2018 by via donau
//   – Österreichische Wasserstraßen-Gesellschaft mbH
// Software engineering by Intevation GmbH
//
// Author(s):
//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>

package common

import (
	"bytes"
	"crypto/rand"
	"io"
	"math"
	"math/big"
	mrand "math/rand"
	"time"

	"gemma.intevation.de/gemma/pkg/log"
)

// GenerateRandomKey generates a cryptographically secure random key
// of a given length.
func GenerateRandomKey(length int) []byte {
	k := make([]byte, length)
	if _, err := io.ReadFull(rand.Reader, k); err != nil {
		return nil
	}
	return k
}

// RandomString generates a cryptographically secure password
// of a given length which consists of alpha numeric characters
// and at least one 'special' one.
func RandomString(n int) string {

	const (
		special  = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
		alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
			"abcdefghijklmnopqrstuvwxyz" +
			"0123456789" +
			special
	)

	max := big.NewInt(int64(len(alphabet)))
	out := make([]byte, n)

	for i := 0; i < 1000; i++ {
		for i := range out {
			v, err := rand.Int(rand.Reader, max)
			if err != nil {
				log.Panicf("%v\n", err)
			}
			out[i] = alphabet[v.Int64()]
		}
		// Ensure at least one special char.
		if bytes.ContainsAny(out, special) {
			return string(out)
		}
	}
	log.Warnf("Your random generator may be broken.")
	out[0] = special[0]
	return string(out)
}

// Random returns a function which generates pseudo random
// values in the range between low and high.
func Random(low, high float64) func() float64 {
	if low > high {
		low, high = high, low
	}

	var seed int64
	if seedInt, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64)); err != nil {
		log.Warnf("Generating good random seed failed: %v\n", err)
		seed = time.Now().Unix()
	} else {
		seed = seedInt.Int64()
	}
	rnd := mrand.New(mrand.NewSource(seed))
	m := high - low
	return func() float64 { return rnd.Float64()*m + low }
}