pax_global_header 0000666 0000000 0000000 00000000064 14357452137 0014525 g ustar 00root root 0000000 0000000 52 comment=8e98d8c18711c6587dce8946985c609a6e2a641b
golang-github-crowdsecurity-machineid-1.0.3/ 0000775 0000000 0000000 00000000000 14357452137 0021100 5 ustar 00root root 0000000 0000000 golang-github-crowdsecurity-machineid-1.0.3/.gitignore 0000664 0000000 0000000 00000000457 14357452137 0023076 0 ustar 00root root 0000000 0000000 # Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
.DS_Store
.vscode
result
/machineid
golang-github-crowdsecurity-machineid-1.0.3/LICENSE.md 0000664 0000000 0000000 00000002072 14357452137 0022505 0 ustar 00root root 0000000 0000000
The MIT License (MIT)
Copyright (c) 2017 Denis Brodbeck
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.
golang-github-crowdsecurity-machineid-1.0.3/README.md 0000664 0000000 0000000 00000012056 14357452137 0022363 0 ustar 00root root 0000000 0000000 # machineid provides support for reading the unique machine id of most host OS's (without admin privileges)

… because sometimes you just need to reliably identify your machines.
## Main Features
* Cross-Platform (tested on Win7+, Debian 8+, Ubuntu 14.04+, OS X 10.6+, FreeBSD 11+)
* No admin privileges required
* Hardware independent (no usage of MAC, BIOS or CPU — those are too unreliable, especially in a VM environment)
* IDs are unique[1](#unique-key-reliability) to the installed OS
## Installation
Get the library with
```bash
go get github.com/crowdsecurity/machineid
```
You can also add the cli app directly to your `$GOPATH/bin` with
## Usage
```golang
package main
import (
"fmt"
"log"
"github.com/crowdsecurity/machineid"
)
func main() {
id, err := machineid.ID()
if err != nil {
log.Fatal(err)
}
fmt.Println(id)
}
```
Or even better, use securely hashed machine IDs:
```golang
package main
import (
"fmt"
"log"
"github.com/crowdsecurity/machineid"
)
func main() {
id, err := machineid.ProtectedID("myAppName")
if err != nil {
log.Fatal(err)
}
fmt.Println(id)
}
```
### Function: ID() (string, error)
Returns original machine id as a `string`.
### Function: ProtectedID(appID string) (string, error)
Returns hashed version of the machine ID as a `string`. The hash is generated in a cryptographically secure way, using a fixed, application-specific key (calculates HMAC-SHA256 of the app ID, keyed by the machine ID).
## What you get
This package returns the OS native machine UUID/GUID, which the OS uses for internal needs.
All machine IDs are usually generated during system installation and stay constant for all subsequent boots.
The following sources are used:
* **BSD** uses `/etc/hostid` and `smbios.system.uuid` as a fallback
* **Linux** uses `/var/lib/dbus/machine-id` ([man](http://man7.org/linux/man-pages/man5/machine-id.5.html))
* **OS X** uses `IOPlatformUUID`
* **Windows** uses the `MachineGuid` from `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
## Unique Key Reliability
Do note, that `machine-id` and `MachineGuid` can be changed by root/admin, although that may not come without cost (broken system services and more).
Most IDs won't be regenerated by the OS, when you clone/image/restore a particular OS installation. This is a well known issue with cloned windows installs (not using the official sysprep tools).
**Linux** users can generate a new id with `dbus-uuidgen` and put the id into `/var/lib/dbus/machine-id` and `/etc/machine-id`.
**Windows** users can use the `sysprep` [toolchain](https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/sysprep--generalize--a-windows-installation) to create images, which produce valid images ready for distribution. Such images produce a new unique machine ID on each deployment.
## Security Considerations
A machine ID uniquely identifies the host. Therefore it should be considered "confidential", and must not be exposed in untrusted environments. If you need a stable unique identifier for your app, do not use the machine ID directly.
> A reliable solution is to hash the machine ID in a cryptographically secure way, using a fixed, application-specific key.
That way the ID will be properly unique, and derived in a constant way from the machine ID but there will be no way to retrieve the original machine ID from the application-specific one.
Do something along these lines:
```golang
package main
import (
"crypto/hmac"
"crypto/sha256"
"fmt"
"github.com/crowdsecurity/machineid"
)
const appKey = "WowSuchNiceApp"
func main() {
id, _ := machineid.ID()
fmt.Println(protect(appKey, id))
// Output: dbabdb7baa54845f9bec96e2e8a87be2d01794c66fdebac3df7edd857f3d9f97
}
func protect(appID, id string) string {
mac := hmac.New(sha256.New, []byte(id))
mac.Write([]byte(appID))
return fmt.Sprintf("%x", mac.Sum(nil))
}
```
Or simply use the convenience API call:
```golang
hashedID, err := machineid.ProtectedID("myAppName")
```
## Snippets
Don't want to download code, and just need a way to get the data by yourself?
BSD:
```bash
cat /etc/hostid
# or (might be empty)
kenv -q smbios.system.uuid
```
Linux:
```bash
cat /var/lib/dbus/machine-id
# or when not found (e.g. Fedora 20)
cat /etc/machine-id
```
OS X:
```bash
ioreg -rd1 -c IOPlatformExpertDevice | grep IOPlatformUUID
```
Windows:
```batch
reg query HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography /v MachineGuid
```
or
* Open Windows Registry via `regedit`
* Navigate to `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`
* Take value of key `MachineGuid`
## Credits
The Go gopher was created by [Denis Brodbeck](https://github.com/denisbrodbeck) with [gopherize.me](https://gopherize.me/), based on original artwork from [Renee French](http://reneefrench.blogspot.com/).
This work is derived from Denis Brodbeck's [original repository](https://github.com/denisbrodbeck/machineid)
## License
The MIT License (MIT) — [Denis Brodbeck](https://github.com/denisbrodbeck). Please have a look at the [LICENSE.md](LICENSE.md) for more details.
golang-github-crowdsecurity-machineid-1.0.3/example_test.go 0000664 0000000 0000000 00000000523 14357452137 0024121 0 ustar 00root root 0000000 0000000 package machineid_test
import (
"fmt"
"log"
"github.com/crowdsecurity/machineid"
)
func Example() {
id, err := machineid.ID()
if err != nil {
log.Fatal(err)
}
fmt.Println(id)
}
func Example_protected() {
appID := "Corp.SomeApp"
id, err := machineid.ProtectedID(appID)
if err != nil {
log.Fatal(err)
}
fmt.Println(id)
}
golang-github-crowdsecurity-machineid-1.0.3/go.mod 0000664 0000000 0000000 00000000160 14357452137 0022203 0 ustar 00root root 0000000 0000000 module github.com/crowdsecurity/machineid
go 1.17
require golang.org/x/sys v0.0.0-20220422013727-9388b58f7150
golang-github-crowdsecurity-machineid-1.0.3/go.sum 0000664 0000000 0000000 00000000317 14357452137 0022234 0 ustar 00root root 0000000 0000000 golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang-github-crowdsecurity-machineid-1.0.3/helper.go 0000664 0000000 0000000 00000001446 14357452137 0022713 0 ustar 00root root 0000000 0000000 package machineid
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"io"
"io/ioutil"
"os"
"os/exec"
"strings"
)
// run wraps `exec.Command` with easy access to stdout and stderr.
func run(stdout, stderr io.Writer, cmd string, args ...string) error {
c := exec.Command(cmd, args...)
c.Stdin = os.Stdin
c.Stdout = stdout
c.Stderr = stderr
return c.Run()
}
// protect calculates HMAC-SHA256 of the application ID, keyed by the machine ID and returns a hex-encoded string.
func protect(appID, id string) string {
mac := hmac.New(sha256.New, []byte(id))
mac.Write([]byte(appID))
return hex.EncodeToString(mac.Sum(nil))
}
func readFile(filename string) ([]byte, error) {
return ioutil.ReadFile(filename)
}
func trim(s string) string {
return strings.TrimSpace(strings.Trim(s, "\n"))
}
golang-github-crowdsecurity-machineid-1.0.3/helper_test.go 0000664 0000000 0000000 00000004326 14357452137 0023752 0 ustar 00root root 0000000 0000000 package machineid
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"strings"
"testing"
)
func Test_protect(t *testing.T) {
appID := "ms.azur.appX"
machineID := "1a1238d601ad430cbea7efb0d1f3d92d"
hash := protect(appID, machineID)
if hash == "" {
t.Error("hash is empty")
}
rawHash, err := hex.DecodeString(hash)
if err != nil {
t.Error(err)
}
eq := checkMAC([]byte(appID), rawHash, []byte(machineID))
if eq == false {
t.Error("hashes do not match")
}
// modify rawHash --> should not match
rawHash[0] = 0
eq = checkMAC([]byte(appID), rawHash, []byte(machineID))
if eq == true {
t.Error("hashes do match, but shouldn't")
}
}
func checkMAC(message, messageMAC, key []byte) bool {
mac := hmac.New(sha256.New, key)
mac.Write(message)
expectedMAC := mac.Sum(nil)
return hmac.Equal(messageMAC, expectedMAC)
}
func Test_run(t *testing.T) {
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
wantStdout := "hello"
wantStderr := ""
if err := run(stdout, stderr, "echo", "hello"); err != nil {
t.Error(err)
}
gotStdout := strings.TrimRight(stdout.String(), "\r\n")
if gotStdout != wantStdout {
t.Errorf("run() = %v, want %v", gotStdout, wantStdout)
}
if gotStderr := stderr.String(); gotStderr != wantStderr {
t.Errorf("run() = %v, want %v", gotStderr, wantStderr)
}
}
func Test_run_unknown(t *testing.T) {
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
err := run(stdout, stderr, "echolo", "hello")
if err == nil {
t.Error("expected error, got none")
}
if strings.Contains(err.Error(), "executable file not found") == false {
t.Error("unexpected error, expected exec not found")
}
}
func Test_trim(t *testing.T) {
type args struct {
s string
}
tests := []struct {
name string
args args
want string
}{
{
name: "nil",
args: args{s: ""},
want: "",
},
{
name: "space",
args: args{s: " space "},
want: "space",
},
{
name: "nl",
args: args{s: "data\n"},
want: "data",
},
{
name: "combined",
args: args{s: " some data \n"},
want: "some data",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := trim(tt.args.s); got != tt.want {
t.Errorf("trim() = %v, want %v", got, tt.want)
}
})
}
}
golang-github-crowdsecurity-machineid-1.0.3/id.go 0000664 0000000 0000000 00000003360 14357452137 0022025 0 ustar 00root root 0000000 0000000 // Package machineid provides support for reading the unique machine id of most OSs (without admin privileges).
//
// https://github.com/denisbrodbeck/machineid
//
// https://godoc.org/github.com/denisbrodbeck/machineid/cmd/machineid
//
// This package is Cross-Platform (tested on Win7+, Debian 8+, Ubuntu 14.04+, OS X 10.6+, FreeBSD 11+)
// and does not use any internal hardware IDs (no MAC, BIOS, or CPU).
//
// Returned machine IDs are generally stable for the OS installation
// and usually stay the same after updates or hardware changes.
//
// This package allows sharing of machine IDs in a secure way by
// calculating HMAC-SHA256 over a user provided app ID, which is keyed by the machine id.
//
// Caveat: Image-based environments have usually the same machine-id (perfect clone).
// Linux users can generate a new id with `dbus-uuidgen` and put the id into
// `/var/lib/dbus/machine-id` and `/etc/machine-id`.
// Windows users can use the `sysprep` toolchain to create images, which produce valid images ready for distribution.
package machineid
import (
"fmt"
)
// ID returns the platform specific machine id of the current host OS.
// Regard the returned id as "confidential" and consider using ProtectedID() instead.
func ID() (string, error) {
id, err := machineID()
if err != nil {
return "", fmt.Errorf("machineid: %v", err)
}
return id, nil
}
// ProtectedID returns a hashed version of the machine ID in a cryptographically secure way,
// using a fixed, application-specific key.
// Internally, this function calculates HMAC-SHA256 of the application ID, keyed by the machine ID.
func ProtectedID(appID string) (string, error) {
id, err := ID()
if err != nil {
return "", fmt.Errorf("machineid: %v", err)
}
return protect(appID, id), nil
}
golang-github-crowdsecurity-machineid-1.0.3/id_bsd.go 0000664 0000000 0000000 00000001527 14357452137 0022660 0 ustar 00root root 0000000 0000000 // +build freebsd netbsd openbsd dragonfly solaris
package machineid
import (
"bytes"
"os"
)
const hostidPath = "/etc/hostid"
// machineID returns the uuid specified at `/etc/hostid`.
// If the returned value is empty, the uuid from a call to `kenv -q smbios.system.uuid` is returned.
// If there is an error an empty string is returned.
func machineID() (string, error) {
id, err := readHostid()
if err != nil {
// try fallback
id, err = readKenv()
}
if err != nil {
return "", err
}
return id, nil
}
func readHostid() (string, error) {
buf, err := readFile(hostidPath)
if err != nil {
return "", err
}
return trim(string(buf)), nil
}
func readKenv() (string, error) {
buf := &bytes.Buffer{}
err := run(buf, os.Stderr, "kenv", "-q", "smbios.system.uuid")
if err != nil {
return "", err
}
return trim(buf.String()), nil
}
golang-github-crowdsecurity-machineid-1.0.3/id_darwin.go 0000664 0000000 0000000 00000001565 14357452137 0023376 0 ustar 00root root 0000000 0000000 // +build darwin
package machineid
import (
"bytes"
"fmt"
"os"
"strings"
)
// machineID returns the uuid returned by `ioreg -rd1 -c IOPlatformExpertDevice`.
// If there is an error running the commad an empty string is returned.
func machineID() (string, error) {
buf := &bytes.Buffer{}
err := run(buf, os.Stderr, "ioreg", "-rd1", "-c", "IOPlatformExpertDevice")
if err != nil {
return "", err
}
id, err := extractID(buf.String())
if err != nil {
return "", err
}
return trim(id), nil
}
func extractID(lines string) (string, error) {
for _, line := range strings.Split(lines, "\n") {
if strings.Contains(line, "IOPlatformUUID") {
parts := strings.SplitAfter(line, `" = "`)
if len(parts) == 2 {
return strings.TrimRight(parts[1], `"`), nil
}
}
}
return "", fmt.Errorf("Failed to extract 'IOPlatformUUID' value from `ioreg` output.\n%s", lines)
}
golang-github-crowdsecurity-machineid-1.0.3/id_darwin_test.go 0000664 0000000 0000000 00000003532 14357452137 0024431 0 ustar 00root root 0000000 0000000 // +build darwin
package machineid
import (
"strings"
"testing"
)
const sampleOutput = `+-o MacBookPro12,1
{
"IOPlatformSystemSleepPolicy" = <534c505402001300841e120004000000001400000004000006000000000000000f2500000000000000004000000040000000100000001000070000$
"compatible" = <"MacBookPro12,1">
"version" = <"1.0">
"board-id" = <"Mac-EEECCCDDD8888AAA">
"IOInterruptSpecifiers" = (<0900000005000000>)
"platform-feature" = <0200000000000000>
"serial-number" = <1111111100000000000000000022222222222d3333333000000000000000000000000000000000000>
"IOInterruptControllers" = ("io-apic-0")
"IOPlatformUUID" = "A3344D1DD-1234-22A1-B123-11AB1C11D111"
"target-type" = <"Mac">
"clock-frequency" = <00e1f505>
"manufacturer" = <"Apple Inc.">
"IOPolledInterface" = "SMCPolledInterface is not serializable"
"IOPlatformSerialNumber" = "CCCCCCCCC"
"system-type" = <02>
"product-name" = <"MacBookPro12,1">
"model" = <"MacBookPro12,1">
"name" = <"/">
"IOBusyInterest" = "IOCommand is not serializable"
}
`
func Test_extractID(t *testing.T) {
want := "A3344D1DD-1234-22A1-B123-11AB1C11D111"
got, err := extractID(sampleOutput)
if err != nil {
t.Error(err)
}
if got != want {
t.Errorf("extractID() = %v, want %v", got, want)
}
}
func Test_extractID_invalidInput(t *testing.T) {
got, err := extractID("invalid input")
if err == nil {
t.Error("expected error, got none")
}
if got != "" {
t.Errorf("expected empty string, got some value %s", got)
}
if strings.Contains(err.Error(), "Failed to extract 'IOPlatformUUID'") == false {
t.Errorf("Got unexpected error: %v", err)
}
}
func Test_machineID(t *testing.T) {
got, err := machineID()
if err != nil {
t.Error(err)
}
if got == "" {
t.Error("Got empty machine id")
}
}
golang-github-crowdsecurity-machineid-1.0.3/id_linux.go 0000664 0000000 0000000 00000001663 14357452137 0023250 0 ustar 00root root 0000000 0000000 // +build linux
package machineid
import "errors"
const (
// dbusPath is the default path for dbus machine id.
dbusPath = "/var/lib/dbus/machine-id"
// dbusPathEtc is the default path for dbus machine id located in /etc.
// Some systems (like Fedora 20) only know this path.
// Sometimes it's the other way round.
dbusPathEtc = "/etc/machine-id"
)
// machineID returns the uuid specified at `/var/lib/dbus/machine-id` or `/etc/machine-id`.
// If there is an error reading the files an empty string is returned.
// See https://unix.stackexchange.com/questions/144812/generate-consistent-machine-unique-id
func machineID() (string, error) {
id, err := readFile(dbusPath)
if err != nil || trim(string(id)) == "" {
// try fallback path
id, err = readFile(dbusPathEtc)
}
if err != nil {
return "", err
}
if trim(string(id)) == "" {
return "", errors.New("All known machineid file are empty")
}
return trim(string(id)), nil
}
golang-github-crowdsecurity-machineid-1.0.3/id_test.go 0000664 0000000 0000000 00000000712 14357452137 0023062 0 ustar 00root root 0000000 0000000 package machineid
import "testing"
func TestID(t *testing.T) {
got, err := ID()
if err != nil {
t.Error(err)
}
if got == "" {
t.Error("Got empty machine id")
}
}
func TestProtectedID(t *testing.T) {
id, err := ID()
if err != nil {
t.Error(err)
}
hash, err := ProtectedID("app.id")
if err != nil {
t.Error(err)
}
if hash == "" {
t.Error("Got empty machine id hash")
}
if id == hash {
t.Error("id and hashed id are the same")
}
}
golang-github-crowdsecurity-machineid-1.0.3/id_windows.go 0000664 0000000 0000000 00000001112 14357452137 0023570 0 ustar 00root root 0000000 0000000 // +build windows
package machineid
import (
"golang.org/x/sys/windows/registry"
)
// machineID returns the key MachineGuid in registry `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`.
// If there is an error running the commad an empty string is returned.
func machineID() (string, error) {
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Cryptography`, registry.QUERY_VALUE|registry.WOW64_64KEY)
if err != nil {
return "", err
}
defer k.Close()
s, _, err := k.GetStringValue("MachineGuid")
if err != nil {
return "", err
}
return s, nil
}
golang-github-crowdsecurity-machineid-1.0.3/logo.png 0000664 0000000 0000000 00000047364 14357452137 0022564 0 ustar 00root root 0000000 0000000 PNG
IHDR ^ 1 W: PLTE @@@ܷe ̽
!!DCC.//б()(&&%YWUƓ=>?##"ffi666nllpiil+,+233ҟqquNNPɆJIJ||yy}cce]]_SSUZZ[ttx``b:::DGJoorxQ˹ġk靝wwzΥVVYۙLTYg좢FMRz6: