commit 0fc01915ae8bc779ea04322a72e6d737a493dbca Author: crusader Date: Thu Apr 12 20:54:56 2018 +0900 ing diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3733e36 --- /dev/null +++ b/.gitignore @@ -0,0 +1,68 @@ +# Created by .ignore support plugin (hsz.mobi) +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties +### Go template +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ +.idea/ +*.iml + +vendor/ +glide.lock +.DS_Store +dist/ +debug diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..2ca2b1d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug", + "type": "go", + "request": "launch", + "mode": "debug", + "remotePath": "", + "port": 2345, + "host": "127.0.0.1", + "program": "${workspaceRoot}/main.go", + "env": {}, + "args": [], + "showLog": true + }, + { + "name": "File Debug", + "type": "go", + "request": "launch", + "mode": "debug", + "remotePath": "", + "port": 2345, + "host": "127.0.0.1", + "program": "${fileDirname}", + "env": {}, + "args": [], + "showLog": true + } + + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..20af2f6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +// Place your settings in this file to overwrite default and user settings. +{ +} \ No newline at end of file diff --git a/auth/authenticator.go b/auth/authenticator.go new file mode 100644 index 0000000..5a5b409 --- /dev/null +++ b/auth/authenticator.go @@ -0,0 +1,211 @@ +package auth + +import ( + "context" + "fmt" + "net/http" + "path" + "sync" + "time" + + "git.loafle.net/commons/configuration-go" + cdr "git.loafle.net/commons/di-go/registry" + logging "git.loafle.net/commons/logging-go" + crc "git.loafle.net/commons/rpc-go/client" + crpj "git.loafle.net/commons/rpc-go/protocol/json" + crr "git.loafle.net/commons/rpc-go/registry" + csswc "git.loafle.net/commons/server-go/socket/web/client" + occa "git.loafle.net/overflow/commons-go/core/annotation" + ocnc "git.loafle.net/overflow/commons-go/noauthprobe/config" + ocncc "git.loafle.net/overflow/commons-go/noauthprobe/constants" + ocpc "git.loafle.net/overflow/commons-go/probe/config" + "git.loafle.net/overflow/probe/auth/info" + _ "git.loafle.net/overflow/probe/auth/service" + "git.loafle.net/overflow/probe/config" +) + +type Authenticator struct { + Config *config.Config + ConfigDir string + + authConfig ocnc.Auth + client *crc.Client + + accpetedChan chan string + deniedChan chan struct{} + tempKeyChan chan string + + stopChan chan struct{} + stopWg sync.WaitGroup +} + +func (a *Authenticator) EndableStart() (<-chan error, error) { + if a.stopChan != nil { + return nil, fmt.Errorf("authenticator already running. Stop it before starting it again") + } + + authConfigPath := path.Join(a.ConfigDir, ocnc.ConfigFileName) + conf := configuration.New() + if configuration.Exists(authConfigPath) { + if err := conf.Load(&a.authConfig, authConfigPath); nil != err { + logging.Logger().Errorf("%s %v", err) + return nil, fmt.Errorf("loading of auth config file[%s] failed", authConfigPath) + } + } + + if nil != a.authConfig.DenyDate { + return nil, fmt.Errorf("cannot start because this probe have been denied from overFlow at %s", a.authConfig.DenyDate.String()) + } + + a.accpetedChan = make(chan string, 1) + a.deniedChan = make(chan struct{}, 1) + a.tempKeyChan = make(chan string, 1) + + if err := a.initClient(); nil != err { + return nil, err + } + + if err := a.client.Start(); nil != err { + return nil, err + } + + endChan := make(chan error) + a.stopChan = make(chan struct{}) + + a.stopWg.Add(1) + go a.handleAuthenticator(endChan) + + return endChan, nil +} + +func (a *Authenticator) Stop(ctx context.Context) error { + if a.stopChan == nil { + return fmt.Errorf("Authenticator: must be started before stopping it") + } + close(a.stopChan) + a.stopWg.Wait() + + a.stopChan = nil + + return nil +} + +func (a *Authenticator) logHeader() string { + return "Authenticator:" +} + +func (a *Authenticator) initService() (crr.RPCInvoker, error) { + cdr.RegisterResource("AccpetedChan", a.accpetedChan) + cdr.RegisterResource("DeniedChan", a.deniedChan) + + services, err := cdr.GetInstancesByAnnotationType(occa.RPCServiceAnnotationType) + if nil != err { + return nil, err + } + + rpcRegistry := crr.NewRPCRegistry() + rpcRegistry.RegisterServices(services...) + + return rpcRegistry, nil +} + +func (a *Authenticator) initClient() error { + _connector := a.Config.Central.Connector.Clone() + connector := _connector.(*csswc.Connectors) + + header := make(map[string][]string) + + switch a.authConfig.State() { + case ocnc.AuthStateTypeRegisterd: + header[ocncc.HTTPRequestHeaderKey_NoAuthProbe_Method] = []string{ocncc.HTTPRequestHeaderValue_NoAuthProbe_Method_Connect} + header[ocncc.HTTPRequestHeaderKey_NoAuthProbe_TempProbeKey] = []string{*a.authConfig.TempKey} + default: + rh, err := info.GetRegistHeader(a.Config.Account.APIKey) + if nil != err { + return err + } + header[ocncc.HTTPRequestHeaderKey_NoAuthProbe_Method] = []string{ocncc.HTTPRequestHeaderValue_NoAuthProbe_Method_Regist} + header[ocncc.HTTPRequestHeaderKey_NoAuthProbe_Info] = []string{rh} + } + + centralURL := fmt.Sprintf("ws://%s:%d", a.Config.Central.Host, a.Config.Central.Port) + + connector.URL = path.Join(centralURL, ocncc.HTTPEntry_Auth) + connector.RequestHeader = header + connector.ResponseHandler = func(res *http.Response) { + switch a.authConfig.State() { + case ocnc.AuthStateTypeNotRegisterd: + tempProbeKey := res.Header.Get(ocncc.HTTPResponseHeaderKey_NoAuthProbe_SetTempProbeKey) + a.tempKeyChan <- tempProbeKey + default: + } + } + + rpcInvoker, err := a.initService() + if nil != err { + return err + } + codec := crpj.NewClientCodec() + + a.client = &crc.Client{ + Connector: connector, + Codec: codec, + RPCInvoker: rpcInvoker, + Name: "Authenticator", + } + + return nil +} + +func (a *Authenticator) handleAuthenticator(endChan chan<- error) { + var err error + defer func() { + if nil != a.client { + err = a.client.Stop(context.Background()) + } + + a.stopWg.Done() + endChan <- err + }() + + for { + select { + case probeKey, ok := <-a.accpetedChan: + if !ok { + return + } + logging.Logger().Infof("%s accepted by central", a.logHeader()) + a.Config.Probe.Key = &probeKey + err = configuration.Save(a.Config, path.Join(a.ConfigDir, ocpc.ConfigFileName), true) + if nil != err { + logging.Logger().Errorf("%s %v", a.logHeader(), err) + } + return + case _, ok := <-a.deniedChan: + if !ok { + return + } + logging.Logger().Infof("%s denied by central", a.logHeader()) + n := time.Now() + a.authConfig.DenyDate = &n + err = configuration.Save(a.authConfig, path.Join(a.ConfigDir, ocnc.ConfigFileName), true) + if nil != err { + logging.Logger().Errorf("%s %v", a.logHeader(), err) + } + return + case tempKey, ok := <-a.tempKeyChan: + if !ok { + return + } + logging.Logger().Infof("%s registered by central", a.logHeader()) + a.authConfig.TempKey = &tempKey + err = configuration.Save(a.authConfig, path.Join(a.ConfigDir, ocnc.ConfigFileName), true) + if nil != err { + logging.Logger().Errorf("%s %v", a.logHeader(), err) + return + } + case <-a.stopChan: + return + } + } +} diff --git a/auth/info/info.go b/auth/info/info.go new file mode 100644 index 0000000..9cfe761 --- /dev/null +++ b/auth/info/info.go @@ -0,0 +1,121 @@ +package info + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "errors" + "net" + + "git.loafle.net/commons/util-go/net/gateway" + noauthprobeM "git.loafle.net/overflow/commons-go/noauthprobe/model" + "github.com/shirou/gopsutil/host" +) + +func GetRegistHeader(apiKey string) (string, error) { + var err error + nap := noauthprobeM.NoAuthProbe{ + APIKey: apiKey, + } + + var napd *noauthprobeM.NoAuthProbeDescription + if napd, err = getDescription(); nil != err { + return "", err + } + + var buf []byte + if buf, err = json.Marshal(napd); nil != err { + return "", err + } + nap.Description = string(buf) + + if buf, err = json.Marshal(nap); nil != err { + return "", err + } + + enc := base64.StdEncoding.EncodeToString(buf) + + return enc, nil +} + +func getDescription() (*noauthprobeM.NoAuthProbeDescription, error) { + var err error + napd := &noauthprobeM.NoAuthProbeDescription{} + + if napd.Host, err = getHost(); nil != err { + return nil, err + } + + if napd.Network, err = getNetwork(); nil != err { + return nil, err + } + + return napd, nil +} + +func getHost() (*noauthprobeM.NoAuthProbeDescriptionHost, error) { + if i, err := host.Info(); nil == err { + h := &noauthprobeM.NoAuthProbeDescriptionHost{} + + h.Name = i.Hostname + h.OS = i.OS + h.Platform = i.Platform + h.PlatformFamily = i.PlatformFamily + h.KernelVersion = i.KernelVersion + h.HostID = i.HostID + + return h, nil + } else { + return nil, err + } +} + +func getNetwork() (*noauthprobeM.NoAuthProbeDescriptionNetwork, error) { + var ip net.IP + var iface string + var err error + if ip, iface, err = gateway.DiscoverGateway(); nil != err { + return nil, err + } + + interfaces, err := net.Interfaces() + if err != nil { + return nil, err + } + + idx := -1 + + for _idx, i := range interfaces { + if i.Name == iface { + idx = _idx + break + } + } + + if -1 == idx { + return nil, errors.New("Interface of gateway is not exist") + } + + n := &noauthprobeM.NoAuthProbeDescriptionNetwork{} + + i := interfaces[idx] + + n.Name = i.Name + n.MacAddress = i.HardwareAddr.String() + n.Gateway = ip.String() + + if addrs, err := i.Addrs(); nil == err { + var buffer bytes.Buffer + for _idx, a := range addrs { + if 0 < _idx { + buffer.WriteString("|") + } + buffer.WriteString(a.String()) + } + n.Address = buffer.String() + } else { + return nil, err + } + + return n, nil +} diff --git a/auth/service/auth-service.go b/auth/service/auth-service.go new file mode 100644 index 0000000..cafde8c --- /dev/null +++ b/auth/service/auth-service.go @@ -0,0 +1,32 @@ +package service + +import ( + "reflect" + + cda "git.loafle.net/commons/di-go/annotation" + cdr "git.loafle.net/commons/di-go/registry" + _ "git.loafle.net/overflow/commons-go/core/annotation" +) + +var AuthServiceType = reflect.TypeOf((*AuthService)(nil)) + +func init() { + cdr.RegisterType(AuthServiceType) +} + +type AuthService struct { + cda.TypeAnnotation `annotation:"@overflow:RPCService()"` + + AcceptedChan chan<- string + DeniedChan chan<- struct{} +} + +func (as *AuthService) Accept(probeKey string) error { + as.AcceptedChan <- probeKey + return nil +} + +func (as *AuthService) Deny() error { + as.DeniedChan <- struct{}{} + return nil +} diff --git a/auth/service/service.go b/auth/service/service.go new file mode 100644 index 0000000..3713b70 --- /dev/null +++ b/auth/service/service.go @@ -0,0 +1,13 @@ +package service + +func InitPackage() { +} + +func StartPackage() { +} + +func StopPackage() { +} + +func DestroyPackage() { +} diff --git a/config.json b/config.json new file mode 100644 index 0000000..f175db1 --- /dev/null +++ b/config.json @@ -0,0 +1,37 @@ +{ + "account": { + "name": "domain1", + "apiKey": "52abd6fd57e511e7ac52080027658d13" + }, + "central": { + "host": "127.0.0.1", + "port": 19190, + "connector": { + "handshakeTimeout": 0, + "reconnectInterval": 5, + "reconnectTryTime": 10, + "maxMessageSize": 4096, + "readBufferSize": 4096, + "writeBufferSize": 4096, + "readTimeout": 0, + "writeTimeout": 0, + "pongTimeout": 60, + "pingTimeout": 10, + "pingPeriod": 9, + "enableCompression": false + }, + "proxy": { + "host": "", + "port": 9090, + "useAuth": true, + "user": "", + "password": "" + } + }, + "probe": { + "key": "866f9be0333311e8b7230242ac120004" + }, + "paths": { + "root": "/project/overFlow/probe" + } +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..a1fa122 --- /dev/null +++ b/config/config.go @@ -0,0 +1,12 @@ +package config + +import ( + ocpc "git.loafle.net/overflow/commons-go/probe/config" +) + +type Config struct { + Account *ocpc.Account `required:"true" json:"account" yaml:"account" toml:"account"` + Central *ocpc.Central `required:"true" json:"central" yaml:"central" toml:"central"` + Probe *ocpc.Probe `required:"true" json:"probe" yaml:"probe" toml:"probe"` + Paths map[string]string `required:"true" json:"paths" yaml:"paths" toml:"paths"` +} diff --git a/glide.yaml b/glide.yaml new file mode 100644 index 0000000..cbfd42e --- /dev/null +++ b/glide.yaml @@ -0,0 +1,6 @@ +package: git.loafle.net/overflow/probe +import: +- package: git.loafle.net/commons/logging-go +- package: git.loafle.net/commons/configuration-go +- package: git.loafle.net/commons/rpc-go +- package: git.loafle.net/commons/server-go diff --git a/main.go b/main.go new file mode 100644 index 0000000..6f51430 --- /dev/null +++ b/main.go @@ -0,0 +1,79 @@ +package main + +import ( + "context" + "flag" + "os" + "os/signal" + "syscall" + "time" + + "git.loafle.net/commons/configuration-go" + "git.loafle.net/commons/logging-go" + + occi "git.loafle.net/overflow/commons-go/core/interfaces" + ocpc "git.loafle.net/overflow/commons-go/probe/config" + "git.loafle.net/overflow/probe/auth" + "git.loafle.net/overflow/probe/config" +) + +var ( + configDir *string +) + +func init() { + configDir = flag.String("config-dir", "./", "Config directory") + logConfigPath := flag.String("log-config", "", "logging config path") + flag.Parse() + + logging.InitializeLogger(*logConfigPath) +} + +func main() { + _config := &config.Config{} + configuration.SetConfigPath(*configDir) + if err := configuration.Load(_config, ocpc.ConfigFileName); nil != err { + logging.Logger().Panic(err) + } + + var instance interface{} + + go func() { + if ocpc.ProbeStateTypeNotAuthorized == _config.Probe.State() { + instance = &auth.Authenticator{ + ConfigDir: *configDir, + Config: _config, + } + doneChan, err := instance.(occi.EndableStarter).EndableStart() + if nil != err { + logging.Logger().Panic(err) + + } + err = <-doneChan + if nil != err { + logging.Logger().Panic(err) + } + } + + // err := s.ListenAndServe() + // if nil != err { + // log.Printf("err: %v", err) + // } + }() + + interrupt := make(chan os.Signal, 1) + signal.Notify(interrupt, + syscall.SIGKILL, + syscall.SIGSTOP, + syscall.SIGHUP, + syscall.SIGINT, + syscall.SIGTERM, + syscall.SIGQUIT) + + <-interrupt + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := instance.(occi.Stopper).Stop(ctx); err != nil { + logging.Logger().Errorf("error: %v", err) + } +}