commit fbaf9393eafb9d3bd9b2539df4f2b9e4e88c4e50 Author: Zeev Diukman Date: Sun Mar 2 16:14:03 2025 +0000 first diff --git a/.air.toml b/.air.toml new file mode 100644 index 0000000..a924b80 --- /dev/null +++ b/.air.toml @@ -0,0 +1,52 @@ +root = "." +testdata_dir = "testdata" +tmp_dir = "tmp" + +[build] + args_bin = [] + bin = "./tmp/main" + cmd = "go build -o ./tmp/main ./cmd/server/." + delay = 1000 + exclude_dir = ["assets", "tmp", "vendor", "testdata","docker"] + exclude_file = [] + exclude_regex = ["_test.go"] + exclude_unchanged = false + follow_symlink = false + full_bin = "" + include_dir = [] + include_ext = ["go", "tpl", "tmpl", "html","yml","yaml"] + include_file = [] + kill_delay = "0s" + log = "build-errors.log" + poll = false + poll_interval = 0 + post_cmd = [] + pre_cmd = [] + rerun = false + rerun_delay = 500 + send_interrupt = false + stop_on_error = false + +[color] + app = "" + build = "yellow" + main = "magenta" + runner = "green" + watcher = "cyan" + +[log] + main_only = false + silent = false + time = false + +[misc] + clean_on_exit = false + +[proxy] + app_port = 0 + enabled = false + proxy_port = 0 + +[screen] + clear_on_rebuild = false + keep_scroll = true diff --git a/.env b/.env new file mode 100644 index 0000000..68b1f9e --- /dev/null +++ b/.env @@ -0,0 +1,16 @@ +# Keycloak openid provider configuration +KEYCLOAK_REALM=dev +KEYCLOAK_CLIENT_ID=dev_client +KEYCLOAK_CLIENT_SECRET=dWhSJgARBAuBAXN7sUTpqpIq2sKQdugs +KEYCLOAK_HOST_URL=http://192.168.10.2:8080 +KEYCLOAK_REDIRECT_URI=https://app.z.com/auth/callback + +# session configuration +SESSION_SECRET=dbemG9m84LmgdYLj4o_wai9Mz18QFHSNZeH92lgxytE +SECRET_KEY=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwSuI+Iyxl4vUzFniKCJQfxAKzvx0wioUlPZc7YsFYGHQ9vIhTNI3kdSD75El6VYy3QSt1jHo/6fu1Oy5Brj95KFf496IQZ3gTLOpu3yVcB55r8nuO07o/9aOex4XItV9Gs9gqdTTq8p5uQrBH1ykq6fCDU57qLCWhijT04MN3DlgRTaNCY2h7XVxmiPORgz+JCAz4OcDM3Xq/ejWZToX+aphYVWIQRxU1mzyq9BuKZzU5tJIkVDQDhDZQyZNY61q4MHfqMKRUS6+5fJZbQWcgt3/4B+yUp/oVlmJjaEMuFDPyzZCHtm+r1Idw/ajMTzlwOFbnj6/8qteFIP/b9uWdQIDAQAB + +# Auth configuration +AUTH_PREFIX=/auth +CALLBACK_PATH=/callback +LOGIN_PATH=/login +LOGOUT_PATH=/logout diff --git a/cmd/server/functions.go b/cmd/server/functions.go new file mode 100644 index 0000000..4df65cd --- /dev/null +++ b/cmd/server/functions.go @@ -0,0 +1,14 @@ +package main + +import ( + "crypto/tls" +) + +// loadCertificate dynamically loads the certificate from files +func loadCertificate(certFile, keyFile string) (tls.Certificate, error) { + cert, err := tls.LoadX509KeyPair(certFile, keyFile) + if err != nil { + return tls.Certificate{}, err + } + return cert, nil +} diff --git a/cmd/server/main.go b/cmd/server/main.go new file mode 100644 index 0000000..3482d19 --- /dev/null +++ b/cmd/server/main.go @@ -0,0 +1,437 @@ +package main + +import ( + "context" + "crypto/rand" + "crypto/sha256" + "crypto/tls" + "encoding/base64" + "encoding/json" + "errors" + "io" + "log" + "net/http" + "net/http/httputil" + "net/url" + "strings" + "time" + + "github.com/coreos/go-oidc/v3/oidc" + "github.com/gookit/goutil/dump" + "zeevdiukman.com/zprox/internal/config" + "zeevdiukman.com/zprox/internal/logic" + "zeevdiukman.com/zprox/internal/reverse_proxy" + "zeevdiukman.com/zprox/internal/router" + "zeevdiukman.com/zprox/pkg/helper" +) + +const DEVELOPMENT bool = true + +type EntryPoints map[string]EntryPoint +type EntryPoint struct { + Name string + Group string + *http.Server +} +type ReverseProxies map[string]ReverseProxy +type ReverseProxy *httputil.ReverseProxy + +var app = logic.NewApp() + +func main() { + helper.AppRunner(func() { + config.Wrapper(func(c *config.Config) { + groups := logic.NewGroups() + mainRouter := router.New() + groups.ForEach(func(k string, g *logic.Group) { + groupSubRouter := mainRouter.Mux.NewRoute().Subrouter() + // groupSubRouter.Use(Domain) + for k := range g.ReverseProxies { + rpConfig := c.ReverseProxies[k] + domain := rpConfig.Domain + proxy := reverse_proxy.New(rpConfig.Host) + proxy.Name = domain + newRoute := groupSubRouter.NewRoute() + subRouter := newRoute.Host(domain).Subrouter() + + if rpConfig.Auth != "" { + if _, ok := c.Auth[rpConfig.Auth]; !ok { + err := errors.New("Error: Auth " + rpConfig.Auth + " not exist!") + panic(err.Error()) + } + pths := c.Auth[rpConfig.Auth].Paths + authRoute := subRouter.NewRoute() + subRouter.Use(Middleware_SetHeaders) + authSubRouter := authRoute.PathPrefix(pths.Prefix).Subrouter() + authSubRouter.Path(pths.Login).Handler(http.HandlerFunc(LoginHandler)) + authSubRouter.Path(pths.Logout).Handler(http.HandlerFunc(LogoutHandler)) + authSubRouter.Path(pths.Callback).Handler(http.HandlerFunc(CallbackHandler)) + subRouter.Use(authMiddleware) + } + subRouter.PathPrefix("/").Handler(proxy.Httputil) + + } + + if len(g.ReverseProxies) > 0 { + tlsConfig := &tls.Config{ + + GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { + // crt, key := "", "" + + crt, key := c.GetCertsPairByDomain(info.ServerName) + + if crt == "" && key == "" { + // crt = c.TLS.Certs["default"].Cert + // key = c.TLS.Certs["default"].Key + // panic("Error: TLS cert and key not found!") + + } + cert, err := loadCertificate(crt, key) + if err != nil { + return nil, err + } + return &cert, nil + }, + } + server := &http.Server{ + Addr: ":" + g.Port, + Handler: app.SessionManager.LoadAndSave(groupSubRouter), + TLSConfig: tlsConfig, + } + var err error + go func() { + ipAddr := helper.GetIP() + log.Println("Test server is running at http://" + ipAddr + ":" + g.Port) + if g.TLS { + err = server.ListenAndServeTLS("", "") + } else { + err = server.ListenAndServe() + } + if err != nil { + log.Println(err.Error()) + } + }() + } + + }) + helper.StartTestHTTPServer(3000) + }) + }) +} + +// ////////////////////////////////////////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////////////////////////////////////////// + +func authMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + config.Wrapper(func(c *config.Config) { + currentPath := r.URL.Path + authName := c.GetAuthNameByDomain(r.Host) + // authName := c.DataMaps.DomainToAuth[r.Host] + loginPath := c.Auth[authName].Paths.Prefix + c.Auth[authName].Paths.Login + logoutPath := c.Auth[authName].Paths.Prefix + c.Auth[authName].Paths.Logout + callbackPath := c.Auth[authName].Paths.Prefix + c.Auth[authName].Paths.Callback + // loginPath := c.Auth[authName].Paths.Prefix + c.Auth[authName].Paths.Login + // logoutPath := c.Auth[authName].Paths.Prefix + c.Auth[authName].Paths.Logout + // callbackPath := c.Auth[authName].Paths.Prefix + c.Auth[authName].Paths.Callback + // TODO: mark auth reverse proxy in yaml + // AuthHostUrl, _ := url.Parse(c.Auth.Default.OpenID.Host) + + if r.Host == "keycloak.z.com" { + next.ServeHTTP(w, r) + } + switch currentPath { + case loginPath: + { + // fmt.Fprintln(w, "LOGIN") + next.ServeHTTP(w, r) + + } + case logoutPath: + { + next.ServeHTTP(w, r) + // return + } + case callbackPath: + { + next.ServeHTTP(w, r) + // return + } + default: + { + accessToken := app.SessionManager.GetString(r.Context(), "access_token") + if accessToken == "" { + authName := c.DataMaps.DomainToAuth[r.Host] + http.Redirect(w, r, c.Auth[authName].Paths.Prefix+c.Auth[authName].Paths.Login, http.StatusFound) + return + } + // auth.SetAuthHeader(w, accessToken) + a := c.Auth[authName] + pths := a.Paths + prefix := pths.Prefix + login := pths.Login + logout := pths.Logout + loginPath := prefix + login + logoutPath := prefix + logout + if loginPath == r.URL.Path || logoutPath == r.URL.Path { + next.ServeHTTP(w, r) + // return + } + + // tokenOk := IsAuthorizedJWT(accessToken, c, "default") + // if tokenOk { + // } else { + // // p := a.OpenID + // // Redirect to login + // } + next.ServeHTTP(w, r) + } + } + }) + }) + +} + +func Domain(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // c := config.New().Auth.Default.Paths + + // requestedPath := r.URL.Path + // a := c + // excludedPaths := []string{ + // a.Prefix + a.Login, + // a.Prefix + a.Callback, + // a.Prefix + a.Logout, + // } + // contains := helper.IsSliceContains(excludedPaths, requestedPath) + // if !contains { + // app.SessionManager.Put(r.Context(), "original_path", requestedPath) + // } + next.ServeHTTP(w, r) + }) +} + +func Middleware_SetHeaders(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + r.Header.Set("X-Forwarded-Proto", getProto(r)) + r.Header.Set("X-Forwarded-For", r.RemoteAddr) + r.Header.Set("X-Forwarded-Host", r.Host) + r.Header.Set("X-Real-IP", r.RemoteAddr) + next.ServeHTTP(w, r) + }) +} +func getProto(req *http.Request) string { + if req.TLS != nil { + return "https" + } else { + return "http" + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +type TokenResponse struct { + AccessToken string `json:"access_token"` + ExpiresIn int `json:"expires_in"` + RefreshExpiresIn int `json:"refresh_expires_in"` + TokenType string `json:"token_type"` + NotBeforePolicy int `json:"not-before-policy"` + SessionState string `json:"session_state"` + Scope string `json:"scope"` + RefreshToken string `json:"refresh_token"` + Error string `json:"error"` + ErrorDescription string `json:"error_description"` +} + +type Res401Struct struct { + Status string `json:"status" example:"FAILED"` + HTTPCode int `json:"httpCode" example:"401"` + Message string `json:"message" example:"authorisation failed"` +} + +type Claims struct { + ResourceAccess client `json:"resource_access,omitempty"` + JTI string `json:"jti,omitempty"` +} + +type client struct { + DemoServiceClient clientRoles `json:"DemoServiceClient,omitempty"` +} + +type clientRoles struct { + Roles []string `json:"roles,omitempty"` +} +type HandlerFuncConfigWrapper func(*config.Config, http.ResponseWriter, *http.Request) *http.Handler + +// HANDLERS +// //////////// +func CallbackHandler(w http.ResponseWriter, r *http.Request) { + config.Wrapper(func(c *config.Config) { + query := r.URL.Query() + code := query.Get("code") + state := query.Get("state") + verifier := app.SessionManager.GetString(r.Context(), "code_verifier") + if verifier == "" { + http.Error(w, "Code verifier not found in session", http.StatusBadRequest) + return + } + expectedState := app.SessionManager.GetString(r.Context(), "state") + if state != expectedState { + http.Error(w, "Invalid state parameter", http.StatusBadRequest) + return + } + originalPath := app.SessionManager.GetString(r.Context(), "original_path") + authName := c.GetAuthNameByDomain(r.Host) + token, fullResponse, e := exchangeCode(code, verifier, c, authName) + if e != nil { + dump.Println("exchangeCode: " + e.Error()) + } + + app.SessionManager.Put(r.Context(), "access_token", token.AccessToken) + app.SessionManager.Put(r.Context(), "full_token", fullResponse) + + // SetAuthHeader(w, token.AccessToken) + http.Redirect(w, r, originalPath, http.StatusFound) + }) +} +func LogoutHandler(w http.ResponseWriter, r *http.Request) { + config.Wrapper(func(c *config.Config) { + app.SessionManager.Remove(r.Context(), "access_token") + app.SessionManager.Remove(r.Context(), "full_token") + authName := c.DataMaps.DomainToAuth[r.Host] + a := c.Auth[authName] + u := a.OpenID.EndPoints.Logout + http.Redirect(w, r, u, http.StatusFound) + }) + +} + +func LoginHandler(w http.ResponseWriter, r *http.Request) { + config.Wrapper(func(c *config.Config) { + authName := c.DataMaps.DomainToAuth[r.Host] + codeVerifier, _ := generateCodeVerifier() + codeChallenge := generateCodeChallenge(codeVerifier) + state := helper.RandStringByBits(128) + nonce := helper.RandStringByBits(128) + authURL, _ := url.Parse(c.Auth[authName].OpenID.EndPoints.Auth) + query := authURL.Query() + query.Set("client_id", c.Auth[authName].OpenID.ClientID) + query.Set("response_type", "code") + query.Set("scope", "openid") + query.Set("redirect_uri", c.Auth[authName].OpenID.RedirectURI) + query.Set("code_challenge", codeChallenge) + query.Set("code_challenge_method", "S256") + query.Set("state", state) + query.Set("nonce", nonce) + authURL.RawQuery = query.Encode() + app.SessionManager.Put(r.Context(), "state", state) + app.SessionManager.Put(r.Context(), "code_verifier", codeVerifier) + http.Redirect(w, r, authURL.String(), http.StatusFound) + }) + +} + +// AUTH FUNCTIONS +//////////////////// + +func exchangeCode(code string, verifier string, c *config.Config, authName string) (*TokenResponse, string, error) { + data := url.Values{} + data.Set("grant_type", "authorization_code") + data.Set("client_id", c.Auth[authName].OpenID.ClientID) + data.Set("client_secret", c.Auth[authName].OpenID.ClientSecert) + data.Set("redirect_uri", c.Auth[authName].OpenID.RedirectURI) + data.Set("code", code) + data.Set("scope", "openid zapp") + if verifier != "" { + data.Set("code_verifier", verifier) + } + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: DEVELOPMENT}, + } + client := &http.Client{Transport: tr} + u := c.Auth[authName].OpenID.EndPoints.Token + r, _ := http.NewRequest(http.MethodPost, u, strings.NewReader(data.Encode())) + r.Header.Add("Content-Type", "application/x-www-form-urlencoded") + resp, err := client.Do(r) + + if err != nil { + dump.Println("ERROR exchange code: " + err.Error()) + return nil, "", err + } + respBytes, err := io.ReadAll(resp.Body) + tokenResponse := &TokenResponse{} + + json.Unmarshal(respBytes, &tokenResponse) + + if err != nil { + dump.Println("ERROR exchange code Unmarshal: " + err.Error()) + return nil, "", err + } + if tokenResponse.Error != "" { + dump.Println(tokenResponse.Error + ": " + tokenResponse.ErrorDescription) + } + fullResponse := string(respBytes) + + return tokenResponse, fullResponse, nil +} + +func generateCodeVerifier() (string, error) { + verifier := make([]byte, 32) + _, err := rand.Read(verifier) + if err != nil { + return "", err + } + return base64.RawURLEncoding.EncodeToString(verifier), nil +} + +func generateCodeChallenge(verifier string) string { + hash := sha256.Sum256([]byte(verifier)) + return base64.RawURLEncoding.EncodeToString(hash[:]) +} + +func IsAuthorizedJWT(rawAccessToken string, c *config.Config, authName string) bool { + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + client := &http.Client{ + Timeout: time.Duration(6000) * time.Second, + Transport: tr, + } + ctx := oidc.ClientContext(context.Background(), client) + provider, err := oidc.NewProvider(ctx, c.Auth[authName].OpenID.EndPoints.Issuer) + if err != nil { + dump.Println("authorisation failed while getting the provider: " + err.Error()) + return false + } + + oidcConfig := &oidc.Config{ + ClientID: c.Auth[authName].OpenID.ClientID, + } + verifier := provider.Verifier(oidcConfig) + idToken, err := verifier.Verify(ctx, rawAccessToken) + if err != nil { + dump.Println("authorisation failed while verifying the token: " + err.Error()) + return false + } + + var IDTokenClaims Claims // ID Token payload is just JSON. + if err := idToken.Claims(&IDTokenClaims); err != nil { + dump.Println("claims: " + err.Error()) + return false + } + return true +} + +/////////////////////////////////// +/////////////////////////////////// diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..36e54ba --- /dev/null +++ b/config.yml @@ -0,0 +1,81 @@ +reverse_proxies: + + kc: + domain: keycloak.z.com + host: http://127.0.0.1:8080 + entry_point: https + tls: + enabled: true + certs: default + + + app: + domain: app.z.com + host: http://127.0.0.1:3000 + entry_point: https + tls: + enabled: true + certs: default + auth: default + +tls: + certs: + default: + cert: z.com.cert.pem + key: z.com.key.pem + +entry_points: + https: + tls: true + port: 443 + http: + port: 80 + +auth: + default: + paths: + prefix: /auth + login: /login + logout: /logout + callback: /callback + open_id: + host: http://127.0.0.1:8080 + realm: dev + client_id: dev_client + client_secret: dWhSJgARBAuBAXN7sUTpqpIq2sKQdugs + redirect_uri: https://app.z.com/auth/callback + post_logout_redirect_uri: https://app.z.com/auth/logout + config_path: /realms/{{realm}}/.well-known/openid-configuration + # config_fields: + # - issuer + # - authorization_endpoint + # - token_endpoint + # - introspection_endpoint + # - userinfo_endpoint + # - end_session_endpoint + # - jwks_uri + # issuer: http://127.0.0.1:8080/realms/dev + + + +# scope: openid profile email + + # response_type: code + # response_mode: query + # prompt: none + # post_logout_redirect_uri: https://app.z.com/auth/logout + # token_endpoint_auth_method: client_secret_post + # userinfo_endpoint: https://keycloak.z.com/auth/realms/z/protocol/openid-connect/userinfo + # authorization_endpoint: https://keycloak.z.com/auth/realms/z/protocol/openid-connect/auth + # token_endpoint: https://keycloak.z.com/auth/realms/z/protocol/openid-connect/token + # end_session_endpoint: https://keycloak.z.com/auth/realms/z/protocol/openid-connect/logout + # jwks_uri: https://keycloak.z.com/auth/realms/z/protocol/openid-connect/certs + # issuer: https://keycloak.z.com/auth/realms/z + # registration_endpoint: https://keycloak.z.com/auth/realms/z/clients-registrations/openid-connect + # check_session_iframe: https://keycloak.z.com/auth/realms/z/protocol/openid-connect/login-status-iframe.html + # client_name: zapp + # client_uri: https://app.z.com + # logo_uri: https://app.z.com/logo.png + # policy_uri: https://app.z.com/policy + # tos_uri: https://app.z.com/tos + # jwks: https://keycloak.z.com/auth/realms/z/protocol/openid-connect/certs diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..683becd --- /dev/null +++ b/go.mod @@ -0,0 +1,38 @@ +module zeevdiukman.com/zprox + +go 1.24.0 + +require ( + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-jose/go-jose/v4 v4.0.2 // indirect + github.com/gookit/color v1.5.4 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +require ( + github.com/alexedwards/scs/v2 v2.8.0 + github.com/coreos/go-oidc/v3 v3.12.0 + github.com/gookit/goutil v0.6.18 + github.com/gorilla/mux v1.8.1 + github.com/spf13/viper v1.19.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..59552cb --- /dev/null +++ b/go.sum @@ -0,0 +1,89 @@ +github.com/alexedwards/scs/v2 v2.8.0 h1:h31yUYoycPuL0zt14c0gd+oqxfRwIj6SOjHdKRZxhEw= +github.com/alexedwards/scs/v2 v2.8.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8= +github.com/coreos/go-oidc/v3 v3.12.0 h1:sJk+8G2qq94rDI6ehZ71Bol3oUHy63qNYmkiSjrc/Jo= +github.com/coreos/go-oidc/v3 v3.12.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk= +github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/gookit/goutil v0.6.18 h1:MUVj0G16flubWT8zYVicIuisUiHdgirPAkmnfD2kKgw= +github.com/gookit/goutil v0.6.18/go.mod h1:AY/5sAwKe7Xck+mEbuxj0n/bc3qwrGNe3Oeulln7zBA= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..1ce23b1 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,178 @@ +package config + +import ( + "encoding/json" + "io" + "log" + "net/http" + "strings" + + "github.com/spf13/viper" + "zeevdiukman.com/zprox/pkg/helper" +) + +const Viper_File_Name string = "config" +const Viper_File_Type string = "yaml" +const Viper_File_Path string = "." + +var c *Config + +func init() { + helper.New().Screen.Clear() + c = createConfig() + +} +func Wrapper(fn func(c *Config)) { + fn(c) +} +func Get() *Config { + return c +} +func createConfig() *Config { + c := &Config{} + c.initViper() + c.setViperOptions(Viper_File_Name, Viper_File_Type, Viper_File_Path) + c.viperReadYaml() + c.viperUnmarshalYaml() + c.initDomainToProxyNameMap() + c.initDomainToProxyAuthName() + c.initDomainToCertName() + c.initOpenIDEndPoints() + return c +} + +func (c *Config) initViper() { + c.Viper = viper.New() +} + +func (c *Config) setViperOptions(fileName string, fileExtention string, filePath string) { + c.Viper.SetConfigName(fileName) + c.Viper.SetConfigType(fileExtention) + c.Viper.AddConfigPath(filePath) +} + +func (c *Config) viperReadYaml() { + err := c.Viper.ReadInConfig() + if err != nil { + log.Fatalf("Error reading config file, %s", err) + } +} +func (c *Config) viperUnmarshalYaml() { + err := c.Viper.Unmarshal(&c) + if err != nil { + log.Fatalf("Unable to decode into struct, %v", err) + } +} + +func (eps *EntryPoints) ForEach(fn func(epName string, epConfig *EntryPoint)) { + for epName, epConfig := range *eps { + fn(epName, &epConfig) + } +} + +func (rp *ReverseProxies) ForEach(fn func(rpName string, rpConfig *ReverseProxy)) { + for rpName, rpData := range *rp { + fn(rpName, &rpData) + } +} + +func (c *Config) fetchEndPointsByAuthName(authName string) map[string]any { + configURL := c.KeycloakWellknownURL(authName) + resp := helper.IsFetchOK[EndPoints](configURL, "", http.Get) + respByes, err := io.ReadAll(resp.Body) + if err != nil { + log.Println(err.Error()) + } + data := map[string]any{} + json.Unmarshal(respByes, &data) + return data +} + +func (c *Config) initOpenIDEndPoints() { + for authName := range c.Auth { + data := c.fetchEndPointsByAuthName(authName) + + c.Auth[authName].OpenID.EndPoints = &EndPoints{ + Issuer: data["issuer"].(string), + Auth: data["authorization_endpoint"].(string), + Introspection: data["introspection_endpoint"].(string), + Token: data["token_endpoint"].(string), + UserInfo: data["userinfo_endpoint"].(string), + Logout: data["end_session_endpoint"].(string), + JwksUri: data["jwks_uri"].(string), + } + + } + +} +func (c *Config) KeycloakWellknownURL(authName string) string { + + if _, ok := c.Auth[authName]; !ok { + return "" + } + hostUrl := c.Auth[authName].OpenID.Host + realm := c.Auth[authName].OpenID.Realm + configPath := c.Auth[authName].OpenID.ConfigPath + u := hostUrl + u += strings.ReplaceAll(configPath, "{{realm}}", realm) + return u +} + +func (c *Config) initDomainToProxyNameMap() { + mp := make(map[string]string) + c.ReverseProxies.ForEach(func(rpName string, rpConfig *ReverseProxy) { + mp[rpConfig.Domain] = rpName + }) + c.DataMaps.DomainToProxy = mp +} +func (c *Config) initDomainToProxyAuthName() { + authMap := map[string]int{} + for authName := range c.Auth { + authMap[authName] = 1 + } + mp := make(map[string]string) + c.ReverseProxies.ForEach(func(rpName string, rpConfig *ReverseProxy) { + if v, ok := authMap[rpConfig.Auth]; ok && v == 1 { + mp[rpConfig.Domain] = rpConfig.Auth + } + }) + c.DataMaps.DomainToAuth = mp +} +func (c *Config) initDomainToCertName() { + crtMap := map[string]int{} + for crtName := range c.TLS.Certs { + crtMap[crtName] = 1 + } + mp := make(map[string]string) + c.ReverseProxies.ForEach(func(rpName string, rpConfig *ReverseProxy) { + if v, ok := crtMap[rpConfig.TLS.Certs]; ok && v == 1 { + mp[rpConfig.Domain] = rpConfig.TLS.Certs + } + mp[rpConfig.Domain] = rpConfig.TLS.Certs + }) + c.DataMaps.DomainToCert = mp +} +func (c *Config) GetAuthNameByDomain(domain string) string { + return c.DataMaps.DomainToAuth[domain] +} +func (c *Config) GetProxyNameByDomain(domain string) string { + return c.DataMaps.DomainToProxy[domain] +} +func (c *Config) GetCertNameByDomain(domain string) string { + return c.DataMaps.DomainToCert[domain] +} +func (c *Config) GetCertsPairByDomain(domain string) (string, string) { + var crt string + var key string + certName := c.DataMaps.DomainToCert[domain] + crt = c.TLS.Certs[certName].Cert + key = c.TLS.Certs[certName].Key + if !(certName != "" && crt == "" && key != "") { + certName = "default" + crt = c.TLS.Certs[certName].Cert + key = c.TLS.Certs[certName].Key + } + + return crt, key + +} diff --git a/internal/config/types.go b/internal/config/types.go new file mode 100644 index 0000000..5f14c3a --- /dev/null +++ b/internal/config/types.go @@ -0,0 +1,93 @@ +package config + +import "github.com/spf13/viper" + +type Config struct { + Viper *viper.Viper + DataMaps DataMaps + ReverseProxies ReverseProxies `mapstructure:"reverse_proxies"` + TLS TLS `mapstructure:"tls"` + EntryPoints EntryPoints `mapstructure:"entry_points"` + Auth map[string]*AuthInstance `mapstructure:"auth"` +} + +type DataMaps struct { + DomainToProxy map[string]string + DomainToAuth map[string]string + DomainToCert map[string]string +} + +// AUTH +// type Auth map[string]AuthInstance + +type AuthInstance struct { + Paths Paths `mapstructure:"paths"` + OpenID OpenID `mapstructure:"open_id"` +} +type Paths struct { + Prefix string `mapstructure:"prefix"` + Login string `mapstructure:"login"` + Logout string `mapstructure:"logout"` + Callback string `mapstructure:"callback"` +} +type OpenID struct { + Host string `mapstructure:"host"` + Realm string `mapstructure:"realm"` + ClientID string `mapstructure:"client_id"` + ClientSecert string `mapstructure:"client_secret"` + RedirectURI string `mapstructure:"redirect_uri"` + PostLogoutRedirectURI string `mapstructure:"post_logout_redirect_uri"` + ConfigPath string `mapstructure:"config_path"` + EndPoints *EndPoints +} + +type EndPoints struct { + Issuer string + Auth string + Introspection string + Token string + UserInfo string + Logout string + JwksUri string +} + +// type OpenIdEndPoints struct { +// Issuer string +// Authorization string +// Token string +// Introspection string +// UserInfo string +// EndSession string +// } + +// ReverseProxies + +type ReverseProxies map[string]ReverseProxy + +type ReverseProxy struct { + Domain string `mapstructure:"domain"` + Host string `mapstructure:"host"` + EntryPoint string `mapstructure:"entry_point"` + TLS TLS_RP `mapstructure:"tls"` + Auth string `mapstructure:"auth"` +} +type TLS_RP struct { + Enabled bool `mapstructure:"enabled"` + Certs string `mapstructure:"certs"` +} + +// TLS +type TLS struct { + Certs map[string]Certs `mapstructure:"certs"` +} +type Certs struct { + Cert string `mapstructure:"cert"` + Key string `mapstructure:"key"` +} + +// EntryPoints +type EntryPoints map[string]EntryPoint +type EntryPoint struct { + Port string `mapstructure:"port"` + TLS bool `mapstructure:"tls"` +} diff --git a/internal/logic/logic.go b/internal/logic/logic.go new file mode 100644 index 0000000..05dd4ce --- /dev/null +++ b/internal/logic/logic.go @@ -0,0 +1,99 @@ +package logic + +import ( + "github.com/alexedwards/scs/v2" + conf "zeevdiukman.com/zprox/internal/config" +) + +var config = conf.Get() + +type App struct { + SessionManager *scs.SessionManager +} + +func (app *App) Get() *App { + return app +} + +func NewApp() *App { + app := &App{ + SessionManager: scs.New(), + } + + return app +} + +type Groups map[string]*Group +type Group struct { + Port string + TLS bool + // ReverseProxies []string + ReverseProxies ReverseProxies + + // Server string + // GroupRouter string +} +type ReverseProxies map[string]ReverseProxy +type ReverseProxy struct { + Certs string +} + +func NewGroups() *Groups { + grps := &Groups{} + grps.initGroups() + return grps +} + +func (grps Groups) ForEach(fn func(k string, g *Group)) { + for k, g := range grps { + fn(k, g) + } +} +func (rpxs ReverseProxies) Get() ReverseProxies { + n := make(ReverseProxies) + for k, v := range rpxs { + n[k] = v + } + return n +} +func (rpxs ReverseProxies) Set(key string, rp ReverseProxy) ReverseProxies { + newProxies := rpxs.Get() + newProxies[key] = rp + return newProxies +} + +// func (rpxs ReverseProxy) Set(newRp *ReverseProxy) { +// rpxs = *newRp +// } + +func (grps Groups) initGroups() { + config.EntryPoints.ForEach(func(epName string, epConfig *conf.EntryPoint) { + if _, ok := grps[epName]; !ok { + grps[epName] = &Group{} + } + grps[epName].TLS = epConfig.TLS + grps[epName].Port = epConfig.Port + }) + config.ReverseProxies.ForEach(func(rpNameA string, rpConfigA *conf.ReverseProxy) { + rps := grps[rpConfigA.EntryPoint].ReverseProxies + certName := rpConfigA.TLS.Certs + // if _, ok := rps[rpNameA]; !ok { + // // grps[rpConfigA.EntryPoint] = &Group{} + // // rps[rpNameA] + // } + rp := ReverseProxy{Certs: certName} + a := insertValue(rps, rpNameA, rp) + grps[rpConfigA.EntryPoint].ReverseProxies = a + }) +} + +func insertValue[T any](mp map[string]T, key string, val T) map[string]T { + n := make(map[string]T) + for k, v := range mp { + n[k] = v + } + n[key] = val + mp = n + return mp + // grps[rpConfigA.EntryPoint].ReverseProxies = a +} diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go new file mode 100644 index 0000000..babd872 --- /dev/null +++ b/internal/middleware/middleware.go @@ -0,0 +1,53 @@ +package middleware + +// import ( +// "net/http" + +// "github.com/alexedwards/scs/v2" +// conf "zeevdiukman.com/zprox/internal/config" +// ) + +// // import ( +// // "net/http" +// // ) + +// func Auth(c *conf.Config, sessionManager *scs.SessionManager) func(http.Handler) http.Handler { +// return func(next http.Handler) http.Handler { +// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// accessToken := sessionManager.GetString(r.Context(), "access_token") +// // auth.SetAuthHeader(w, accessToken) +// loginPath := c.Auth.Prefix + c.Auth.LoginPath +// logoutPath := c.Auth.Prefix + c.Auth.LogoutPath +// if loginPath == r.URL.Path || logoutPath == r.URL.Path { +// next.ServeHTTP(w, r) +// return +// } + +// tokenOk := Domain.IsAuthorizedJWT(accessToken) +// if tokenOk { +// next.ServeHTTP(w, r) +// } else { +// p := c.Auth +// http.Redirect(w, r, p.Prefix+p.LoginPath, http.StatusFound) // Redirect to login +// } + +// }) +// } +// } + +// func Domain(next http.Handler) http.Handler { +// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// // requestedPath := r.URL.Path +// // a := c.Auth +// // excludedPaths := []string{ +// // a.Prefix + a.LoginPath, +// // a.Prefix + a.CallbackPath, +// // a.Prefix + a.LogoutPath, +// // } +// // contains := helper.IsSliceContains(excludedPaths, requestedPath) +// // if !contains { +// // sessionManager.Put(r.Context(), "original_path", requestedPath) +// // } +// next.ServeHTTP(w, r) +// }) +// } diff --git a/internal/reverse_proxy/reverse_proxy.go b/internal/reverse_proxy/reverse_proxy.go new file mode 100644 index 0000000..0e3e6e2 --- /dev/null +++ b/internal/reverse_proxy/reverse_proxy.go @@ -0,0 +1,107 @@ +package reverse_proxy + +import ( + "net/http" + "net/http/httputil" + "net/url" + "strings" + + conf "zeevdiukman.com/zprox/internal/config" +) + +// var config = conf.New() + +type ReverseProxy struct { + Name string + Host string + Httputil *httputil.ReverseProxy +} + +func New(host string) *ReverseProxy { + return &ReverseProxy{ + Host: host, + Httputil: &httputil.ReverseProxy{ + Director: DefaultDirector(host), + }, + } +} + +type Data struct { + Name string + Value any +} +type DirectorFunc func(req *http.Request, data []Data) (*http.Request, []Data) + +func GetData[T any](key string, data []Data) (res T) { + for _, v := range data { + if v.Name == key { + res = v.Value.(T) + } + } + return res +} + +func (rp *ReverseProxy) DefaultDirectorFunc(d []Data, fn DirectorFunc) func(*http.Request) { + return func(r *http.Request) { + host := "" + req, data := fn(r, d) + proxyData := GetData[conf.ReverseProxy]("proxy_data", data) + host = proxyData.Host + target, _ := url.Parse(host) + targetQuery := target.RawQuery + req.URL.Scheme = target.Scheme + req.URL.Host = target.Host + req.URL.Path, req.URL.RawPath = joinURLPath(target, req.URL) + if targetQuery == "" || req.URL.RawQuery == "" { + req.URL.RawQuery = targetQuery + req.URL.RawQuery + } else { + req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery + } + } +} +func DefaultDirector(host string) func(*http.Request) { + return func(req *http.Request) { + target, _ := url.Parse(host) + targetQuery := target.RawQuery + req.URL.Scheme = target.Scheme + req.URL.Host = target.Host + req.URL.Path, req.URL.RawPath = joinURLPath(target, req.URL) + if targetQuery == "" || req.URL.RawQuery == "" { + req.URL.RawQuery = targetQuery + req.URL.RawQuery + } else { + req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery + } + } +} +func joinURLPath(a, b *url.URL) (path, rawpath string) { + if a.RawPath == "" && b.RawPath == "" { + return SingleJoiningSlash(a.Path, b.Path), "" + } + // Same as singleJoiningSlash, but uses EscapedPath to determine + // whether a slash should be added + apath := a.EscapedPath() + bpath := b.EscapedPath() + + aslash := strings.HasSuffix(apath, "/") + bslash := strings.HasPrefix(bpath, "/") + + switch { + case aslash && bslash: + return a.Path + b.Path[1:], apath + bpath[1:] + case !aslash && !bslash: + return a.Path + "/" + b.Path, apath + "/" + bpath + } + return a.Path + b.Path, apath + bpath +} + +func SingleJoiningSlash(a, b string) string { + aslash := strings.HasSuffix(a, "/") + bslash := strings.HasPrefix(b, "/") + switch { + case aslash && bslash: + return a + b[1:] + case !aslash && !bslash: + return a + "/" + b + } + return a + b +} diff --git a/internal/router/router.go b/internal/router/router.go new file mode 100644 index 0000000..7934fc2 --- /dev/null +++ b/internal/router/router.go @@ -0,0 +1,24 @@ +package router + +import "github.com/gorilla/mux" + +func New() *MainRouter { + r := &MainRouter{} + r.SetMux() + return r +} + +func (r *MainRouter) SetMux() { + r.Mux = mux.NewRouter() +} + +type MainRouter struct { + Subrouters Subrouters + Mux *mux.Router +} +type Subrouters map[string]SubRouter +type SubRouter struct { + Name string + Group string + *mux.Router +} diff --git a/pkg/helper/helper.go b/pkg/helper/helper.go new file mode 100644 index 0000000..aba6ec0 --- /dev/null +++ b/pkg/helper/helper.go @@ -0,0 +1,512 @@ +package helper + +import ( + "context" + "crypto/rand" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io" + "log" + "net" + "net/http" + "os" + "os/exec" + "os/signal" + "reflect" + "runtime" + "strconv" + "strings" + "sync" + "syscall" + "time" + "unicode" + + "github.com/gookit/goutil/dump" + "github.com/gorilla/mux" +) + +// const ( +// COLOR_Reset = "\033[0m" +// COLOR_Red = "\033[31m" +// COLOR_Green = "\033[32m" +// COLOR_Yellow = "\033[33m" +// COLOR_Blue = "\033[34m" +// COLOR_Purple = "\033[35m" +// COLOR_Cyan = "\033[36m" +// COLOR_Gray = "\033[37m" +// COLOR_White = "\033[97m" // Brighter white +// ) + +// func Log(msg string) { +// log.New(os.Stdout, msg, log.Ldate|log.Ltime) + +// } +// func Colorize(colorCode string, message string) string { +// return colorCode + message + COLOR_Reset +// } + +type IsStruct struct{} + +var ( + Is IsStruct + h = New() +) + +type Helper struct { + Convert Convert + Struct Struct + Screen Screen + Error Error + If If + Log Log +} +type Convert struct { +} +type Struct struct { +} +type Screen struct { +} +type Error struct { + Val error +} +type If struct { + Error Error +} +type Log struct { + Error Error +} + +func (h *Helper) P(val any) { + dump.Println(val) +} + +// InsertStringValueIntoField inserts a string value into a specified field of a struct. +// +// structPtr must be a pointer to a struct. +// fieldName is the name of the field (case-sensitive). +// stringValue is the string value to be inserted. +// +// Returns an error if: +// - structPtr is not a pointer to a struct. +// - The fieldName is not found in the struct. +// - The field is not settable (e.g., unexported). +// - The field is not of type string. +func New() *Helper { + return &Helper{} +} + +func (e *Error) Log() { + if e.Val != nil { + log.Println(e.Val.Error()) + } +} +func (e *Error) In(err error) *Error { + e.Val = err + return e +} +func (conv *Struct) Insert(structPtr interface{}, param ...any) { + // func (conv *Struct) Insert(structPtr interface{}, fieldName string, stringValue string, sep string) string { + + rawFieldName := param[0].(string) + fieldValue := param[1] + sep := "" + if len(param) > 2 { + sep = param[2].(string) + } else { + sep = "_" + } + // if len(param[2].(string)) > 0 { + // sep = param[2].(string) + // } + seperatorRune := []rune(sep)[0] + field := CapitalizeAfterChar(rawFieldName, seperatorRune) + field = CapitalizeFirstLetter(field) + field = strings.ReplaceAll(field, sep, "") + + err := InsertAnyValueIntoField(structPtr, field, fieldValue) + h.Error.Val = err + h.If.Error.Log() +} +func (conv *Struct) ToStructField(str string, seperator string) string { + seperatorRune := []rune(seperator)[0] + field := CapitalizeAfterChar(str, seperatorRune) + field = CapitalizeFirstLetter(field) + field = strings.ReplaceAll(field, seperator, "") + return field +} +func InsertStringValueIntoField(structPtr interface{}, fieldName string, stringValue string) error { + if structPtr == nil { + return errors.New("structPtr cannot be nil") + } + + val := reflect.ValueOf(structPtr) + if val.Kind() != reflect.Ptr { + return errors.New("structPtr must be a pointer to a struct") + } + + elem := val.Elem() + if elem.Kind() != reflect.Struct { + return errors.New("structPtr must be a pointer to a struct") + } + + fieldVal := elem.FieldByName(fieldName) + if !fieldVal.IsValid() { + return fmt.Errorf("field '%s' not found in struct", fieldName) + } + + if !fieldVal.CanSet() { + return fmt.Errorf("field '%s' is not settable (unexported or embedded without being exported)", fieldName) + } + + if fieldVal.Kind() != reflect.String { + return fmt.Errorf("field '%s' is not a string type", fieldName) + } + + fieldVal.SetString(stringValue) + return nil +} +func InsertAnyValueIntoField(structPtr interface{}, fieldName string, anyValue any) error { + if structPtr == nil { + return errors.New("structPtr cannot be nil") + } + + val := reflect.ValueOf(structPtr) + if val.Kind() != reflect.Ptr { + return errors.New("structPtr must be a pointer to a struct") + } + + elem := val.Elem() + if elem.Kind() != reflect.Struct { + return errors.New("structPtr must be a pointer to a struct") + } + + fieldVal := elem.FieldByName(fieldName) + if !fieldVal.IsValid() { + return fmt.Errorf("field '%s' not found in struct", fieldName) + } + + if !fieldVal.CanSet() { + return fmt.Errorf("field '%s' is not settable (unexported or embedded without being exported)", fieldName) + } + + switch v := anyValue.(type) { + case string: + { + if fieldVal.Kind() != reflect.String { + return fmt.Errorf("field '%s' is not a string type", fieldName) + } + + fieldVal.SetString(v) + return nil + } + case bool: + { + if fieldVal.Kind() != reflect.Bool { + return fmt.Errorf("field '%s' is not a string type", fieldName) + } + + fieldVal.SetBool(v) + return nil + } + } + return fmt.Errorf("value of field '%s' is unknown type", fieldName) +} + +// CapitalizeAfterChar capitalizes the first letter immediately following each occurrence of a specific character in a string. +// +// For example: +// CapitalizeAfterChar("hello_world", '_') == "hello_World" +// CapitalizeAfterChar("this-is-a-test", '-') == "this-Is-A-Test" +// CapitalizeAfterChar(" leading spaces and_underscores", '_') == " leading spaces and_Underscores" +func CapitalizeAfterChar(input string, char rune) string { + var result strings.Builder + capitalizeNext := false // Flag to indicate if the next letter should be capitalized + + for _, r := range input { + if capitalizeNext { + result.WriteRune(unicode.ToUpper(r)) // Capitalize the current rune + capitalizeNext = false // Reset the flag + } else { + result.WriteRune(r) // Write the rune as is + } + + if r == char { + capitalizeNext = true // Set the flag to capitalize the next letter + } + } + return result.String() +} + +func CapitalizeAfterCharMulti(input string, char rune) string { + var result strings.Builder + capitalizeNext := false // Flag to indicate if the next letter should be capitalized + + for _, r := range input { + if capitalizeNext { + result.WriteRune(unicode.ToUpper(r)) // Capitalize the current rune + capitalizeNext = false // Reset the flag + } else { + result.WriteRune(r) // Write the rune as is + } + + if r == char { + capitalizeNext = true // Set the flag to capitalize the next letter + } + } + return result.String() +} + +func CapitalizeFirstLetter(input string) string { + if input == "" { + return input // Return empty string if input is empty + } + + runes := []rune(input) // Convert string to rune slice for Unicode support + firstRune := runes[0] + + if !unicode.IsLetter(firstRune) { + return input // Return original string if first char is not a letter + } + + capitalizedFirstRune := unicode.ToUpper(firstRune) + runes[0] = capitalizedFirstRune + + return string(runes) // Convert rune slice back to string +} +func MapIter[K comparable, V comparable](m map[K]V, fn func(K, V)) { + for p, d := range m { + fn(p, d) + } +} +func (*Screen) Clear() { + if runtime.GOOS == "windows" { + cmd := exec.Command("cmd", "/c", "cls") + cmd.Stdout = os.Stdout + cmd.Run() + } else { + cmd := exec.Command("clear") + cmd.Stdout = os.Stdout + cmd.Run() + } +} + +func RandStringByBits(nBits int) string { + b := make([]byte, nBits/8) + if _, err := io.ReadFull(rand.Reader, b); err != nil { + return err.Error() + } + return base64.RawURLEncoding.EncodeToString(b) +} + +func StructToMap(obj interface{}) map[string]any { + + val := reflect.ValueOf(obj) + typ := reflect.TypeOf(obj) + result := make(map[string]any) + + for i := 0; i < val.NumField(); i++ { + field := typ.Field(i) + result[field.Name] = val.Field(i).Interface() + } + + return result +} + +func FetchGetJson(u string) (map[string]any, error) { + resp, err := http.Get(u) + if err != nil { + return nil, err + } + respByes, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + data := map[string]any{} + json.Unmarshal(respByes, &data) + return data, nil +} + +func GetLastChar(str string) string { + return str[len(str)-1:] +} + +func IsLastChar(str string, chr string) bool { + if l := GetLastChar(str); l == chr { + return true + } + return false + +} + +func IsLastCharDo(str string, chr string, f func(r bool)) bool { + result := IsLastChar(str, chr) + + func(bool) { + f(result) + }(result) + + return result +} + +func IsFetchOK[V any](u string, funcName string, f func(string) (*http.Response, error)) *http.Response { + // errCntr := 0 + errCntrTotal := 0 + var ( + a V + resp *http.Response + err error + ) + for { + resp, err = f(u) + if err == nil && resp.StatusCode == 200 { + // ClearScreen() + break + } else { + // errCntr++ + // errCntrTotal++ + // if errCntr == 10 { + // errCntr = 0 + // ClearScreen() + // } + // if errCntr == 1 { + // ClearScreen() + // } + errCntrTotalStr := strconv.Itoa(errCntrTotal) + pkg := reflect.TypeOf(a).PkgPath() + dt := time.Now() + dateTime := dt.Format("02-01-2006 15:04:05") + fmt.Println("ERROR: " + dateTime + ">---------<" + errCntrTotalStr + ">") + fmt.Println(" :") + fmt.Println(" Package name: " + pkg) + fmt.Println("Function name: " + funcName) + fmt.Println(" URL: " + u) + fmt.Println("Error message: " + err.Error()) + fmt.Println("--------------------------------------") + time.Sleep(5 * time.Second) + } + + } + return resp +} + +func IsSliceContains[T comparable](sliceVals []T, valueToSearch T) bool { + for _, v := range sliceVals { + if v == valueToSearch { + return true + } + } + return false +} + +func AddDotBetween(k ...string) string { + constructedKey := "" + for i, key := range k { + constructedKey += key + if i < len(k)-1 { + constructedKey += "." + } + } + return constructedKey +} + +func RemoveSliceDuplicates(elements []string) []string { + encountered := map[string]bool{} + result := []string{} + + for v := range elements { + if encountered[elements[v]] { + // Do not add duplicate. + } else { + // Record this element as an encountered element. + encountered[elements[v]] = true + // Append to result slice. + result = append(result, elements[v]) + } + } + // Return the new slice. + return result +} + +func IfLast[T any](counter int, someVar map[string]T, fn func()) { + counter++ + if len(someVar) == counter { + fn() + } +} + +func (s *IsStruct) Pointer(v any) bool { + + valueOfP := reflect.ValueOf(v) + if valueOfP.Kind() == reflect.Ptr { + return true + } else { + return false + } +} + +func AppRunner(runApp func()) { + wg := sync.WaitGroup{} + ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) + defer stop() + + runApp() + + <-ctx.Done() + //do stuff after ending + wg.Wait() + fmt.Println("BYE BYE!") + os.Exit(0) +} + +func StartTestHTTPServer(port int) { + p := strconv.Itoa(port) + go func() { + log.Println("Test server is running at http://" + GetIP() + ":" + p) + r := mux.NewRouter() + r.Path("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "/ OK") + }) + r.Path("/test1").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "/test1 OK") + }) + r.Path("/test2").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "/test2 OK") + }) + err := http.ListenAndServe(":3000", r) + if err != nil { + log.Println(err.Error()) + } + }() +} + +func GetIP(prefix ...string) string { + prfx := "192.168." + if len(prefix) > 0 { + prfx = prefix[0] + } + + addrs, err := net.InterfaceAddrs() + if err != nil { + fmt.Println("Error getting interface addresses:", err) + return "" + } + + for _, addr := range addrs { + // Check if the address is an IP address + if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { + + a := strings.HasPrefix(ipnet.IP.String(), prfx) + c := ipnet.IP.To4() != nil + if c && a { //check for ipv4 + prfx = ipnet.IP.String() + break + } + // } else if ipnet.IP.To16() != nil { //check for ipv6 + // fmt.Println("Local IPv6 address:", ipnet.IP.String()) + // } + } + } + return prfx +} diff --git a/tmp/build-errors.log b/tmp/build-errors.log new file mode 100644 index 0000000..2cd73a9 --- /dev/null +++ b/tmp/build-errors.log @@ -0,0 +1 @@ +exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file diff --git a/tmp/main b/tmp/main new file mode 100755 index 0000000..0d7a9ce Binary files /dev/null and b/tmp/main differ diff --git a/z.com.cert.pem b/z.com.cert.pem new file mode 100644 index 0000000..b1ba6b8 --- /dev/null +++ b/z.com.cert.pem @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwcTELMAkGA1UEBhMCSUwx +DjAMBgNVBAgMBUhhaWZhMQ4wDAYDVQQHDAVIYWlmYTEKMAgGA1UECgwBWjEKMAgG +A1UECwwBWjEOMAwGA1UEAwwFei5jb20xGjAYBgkqhkiG9w0BCQEWC2FkbWluQHou +Y29tMB4XDTI1MDIxNjE0NTQ1NloXDTI2MDIyNjE0NTQ1NlowYTELMAkGA1UEBhMC +SUwxDjAMBgNVBAgMBUhhaWZhMQowCAYDVQQKDAFaMQowCAYDVQQLDAFaMQ4wDAYD +VQQDDAV6LmNvbTEaMBgGCSqGSIb3DQEJARYLYWRtaW5Aei5jb20wggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpdNQlUMd1VOeXLYx5bLct+CCEC1XQDboD +DnhQcCOryNGYvOd+u/KyOIKie+TvMCzKSqtv66cy216r4xt1T0w/S5YGhthtM6UA +KZroRRqjuyxt9n+F+u8Mq6wuAYOitWYFSwDlLj+XUM++REljekgYMPJFjRNeshdv +ciAvmgSuba887lcfK9SnkV2GMGetqwtbSxBPPH2nsNl+1yPNrzJw1HatcZiyEF2e +UeseR+yJ8IBqwzalB+GdlPOiy31eKArUYn6F3mWrPpTuJKf8/uAEx4tHkEdeAiaP +lPH8/D2ACExi3bPQBZ0Mu4XlQujSG+vyW2UE6uiMAk+j4xEqCvTVAgMBAAGjggFn +MIIBYzAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIGQDAzBglghkgBhvhCAQ0E +JhYkT3BlblNTTCBHZW5lcmF0ZWQgU2VydmVyIENlcnRpZmljYXRlMB0GA1UdDgQW +BBRoAJ51iApg+pFjY16jj6Nutnw5+jCBrgYDVR0jBIGmMIGjgBSHMJSKqW4qORmC +/Wq8UImiAtuWjaF1pHMwcTELMAkGA1UEBhMCSUwxDjAMBgNVBAgMBUhhaWZhMQ4w +DAYDVQQHDAVIYWlmYTEKMAgGA1UECgwBWjEKMAgGA1UECwwBWjEOMAwGA1UEAwwF +ei5jb20xGjAYBgkqhkiG9w0BCQEWC2FkbWluQHouY29tghQD85U1CPpeLaY/YPkc +xQBVyuU4+zAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwGQYD +VR0RBBIwEIIFei5jb22CByouei5jb20wDQYJKoZIhvcNAQELBQADggIBAF/IKfK8 +dF6qAM0SMr+3K9fEQgJWDfHI2bLFnsFpzRHc5XUGnvp5sRCEXFDJIJSOwGQqv3rm +ylcFVBE4lawtMC/NpMMRSz7/e/NdA/b5CFtCK2EjnM/KYE9EV06EebP0u8yRIppM +Go71j7fAbncVmUwnhLcgIkpb+VKTfexFUIqSVgeXTFkIQa7ndP70W+AUt/5X+Rhy +7c3rE6fklTabMJR8SxQKLz6KJzSJnRLH75H7CxmF2d7NP23HuEfk7OrTRQP+ASmD +VJkzS6GtVQ/MEjVbj9ygABDVmk+0z2prJz1USyqniUhnznQZPOGz0F/M3VUiodsp +rW3YOyPh6Ze8bHih4ivuNTsiXQKSiWWgIP8zEu664hwWtuXZAbVKP3XfLZ5X7gJ2 +Vqj9ulkIa+3VjSv+WA45QZVdBtSoOaNobRaKtjFnK5DWeW6t0e1+DG5PVZe1JTwH +DUxfUEnXDBfsfttqHAHCamWo1dpWzJB9lnTjXHwQHkYYEimTLrPVhzwFV5yegqkP +feMtsgbEsO+QqVSeqx3oy+W2J9tjBwAxrMg1TOMBSWRsaUvwtXwx1cf1bTzjhg9Y +2+dzTmITfxh3tWMh0jYmO1C3PH2K8HKraAXdqrGDbxK94iYpgA5bk48s2H1YCDcF +baYw2irjJC2cmsdGp3an0Mtb8sY4zLbGuRQl +-----END CERTIFICATE----- diff --git a/z.com.key.pem b/z.com.key.pem new file mode 100644 index 0000000..c3b9fc3 --- /dev/null +++ b/z.com.key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCpdNQlUMd1VOeX +LYx5bLct+CCEC1XQDboDDnhQcCOryNGYvOd+u/KyOIKie+TvMCzKSqtv66cy216r +4xt1T0w/S5YGhthtM6UAKZroRRqjuyxt9n+F+u8Mq6wuAYOitWYFSwDlLj+XUM++ +REljekgYMPJFjRNeshdvciAvmgSuba887lcfK9SnkV2GMGetqwtbSxBPPH2nsNl+ +1yPNrzJw1HatcZiyEF2eUeseR+yJ8IBqwzalB+GdlPOiy31eKArUYn6F3mWrPpTu +JKf8/uAEx4tHkEdeAiaPlPH8/D2ACExi3bPQBZ0Mu4XlQujSG+vyW2UE6uiMAk+j +4xEqCvTVAgMBAAECggEALwfSvUyPHxxibk3g9+5ZZLPB6oPu3CCDKMgCUmjdLZc9 +vMNpCH6HXDlc4FW8czoOpFJXBGgF7pJ90vzkKQnKIqMKz2LrfFtiBwqFCMPtIdYX +/aj1Oa0sXXrj/ZzD+QuZdgycAf90/L0b+zWenLJaggRLqUv/PT/2SyMEldGMTRCG +c4+0qdIBhNVPjr6bIX6nOgnexFDFqvfLMy8LHq7LV20xqJDZiu3Xth1BBbCKId+a +rngLU7oGSaIGSfhqLm02F3XPniMktrVkKc00aNzwAOBLLgiWpJzuwcyKCkDhAiBZ +1rfniF6gW/PTWnZ4rscTiF4Dn8iKcr7r7LY+skEuXQKBgQDV9V8tBRnE/qUVqgjK +j0Z7kwhTFWlCaLEqNzfXuV2C2QPYdF4B4nxIUILSMpkgtbDrW7OZBwMk4ac5FCvS +4ok5LcisHs9MgBb4thyf5J+ZKTOM7Z0W+h1MgIs9Bful/PkPHyfNd8rFnhHjGIr9 +05Uqewu8Jwxz8K3hZs1/3fyVlwKBgQDKwOSNCaoWqDi92/vJphoDZOE0vlB3Ti24 +Rg57IlMJZh/l74Qu380E9tC6YidN18yAd4Z9xSBde6ymTdfc8SaID2aIlTZh1kUy +TlWM+JZS5Nzwywb7dBJK/u6+Foe7HsYqUb8Sog/ne6ox0fFIh4thwO1Hh9uUv63L +O80UFXaOcwKBgQDEe4jjtwNrPM4tjvBz1A9N/EBwzADV036e3gaSPM/7EX/Oj06l +PHAVmJoKnhyxRSkrehL8PMxOWktOx49XImIR+FGIfuKvxhFSZSr0Suelp4iHqs3Q +A/BUCNfVOmFWlXHCyUGsFo5H3Flgy3EYl+0sDcNBDjsJXcTQca/V9O24EQKBgBfy +0swp8RI+Cn26hzIZUYdHGia9uAlvjYzvkXRP6Jj6nBfvw6A5xSCp+puZTmUucTRX +aeZfK2R/YDRAi5fIUDHQB99oKIVD5uZ7RDWjgzYFXGeAw7Fd029ST2baiGu8xdFn +2Hbd95zzCXZbAvH7OKZyQFSrom8eeOvBg4a0xk0rAoGBAMYguMmRtSXHNy5VYr02 +JnDUkEEo+qr9pb+z57OqzP1tDVQzjqovy1MQUrI9jLX78lky23P6Qi3mJATu73qo +a14TIRGxPYzfYplhzWqi+LonohKmvRG+Gm6u82abesqgIjUuZmvyxQa7grMi90h8 +p5t8O+ki5NtPp+RAy5pDZg5Z +-----END PRIVATE KEY-----