diff --git a/.github/templates/README.template.md b/.github/templates/README.template.md index 6cfa70a0..20264b14 100644 --- a/.github/templates/README.template.md +++ b/.github/templates/README.template.md @@ -1,11 +1,13 @@ # Secured Signal Api -Secured Signal Api acts as a secured proxy for signal-rest-api. +Secured Signal Api acts as a secure proxy for signal-rest-api. ## Installation Get the latest version of the `docker-compose.yaml` file: +And set `API_TOKEN` to a long secure string + ```yaml { { file.docker-compose.yaml } } ``` @@ -24,44 +26,149 @@ Before you can send messages via `secured-signal-api` you must first setup [`sig to send messages you have to either: -- register a Signal Account +- **register a Signal Account** OR -- link Signal Api to a already registered Signal Device +- **link Signal API to an already registered Signal Device** ## Usage +Secured Signal API implements 3 Ways to Authenticate + +### Bearer + +To Authenticate with `secured-signal-api` add `Authorization: Bearer TOKEN` to your request Headers + +### Basic Auth + +To use Basic Auth as Authorization Method add `Authorization: Basic base64{user:pw}` to your Headers + +### Query Auth + +If you are working with a limited Application you may **not** be able to modify Headers or the Request Body +in this case you should use **Query Auth**. + +Here is a simple example: + +```bash +curl -X POST http://signal-api:8880/v2/send?@authorization=TOKEN +``` + To send a message to `number`: `1234567`: ```bash curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer TOKEN" -d '{"message": "Hello World!", "recipients": ["1234567"]}' http://signal-api:8880/v2/send ``` -### Configuration - -Because `secured-signal-api` is just a secure proxy you can use all of the [Signal REST Api](https://github.com/bbernhard/signal-cli-rest-api/blob/master/doc/EXAMPLES.md) endpoints with an Exception of: - -```python -DEFAULT_BLOCKED_ENDPOINTS = [ - "/v1/about", - "/v1/configuration", - "/v1/devices", - "/v1/register", - "/v1/unregister", - "/v1/qrcodelink", - "/v1/accounts", - "/v1/contacts" -] +### Advanced + +#### Placeholders + +If you are not comfortable with hardcoding your Number and/or Recipients in you may use **Placeholders** in your request like: + +`{{ .NUMBER }}` or `{{ .RECIPIENTS }}` + +These _Placeholders_ can be used in the Query or the Body of a Request like so: + +**Body** + +```json +{ + "number": "{{ .NUMBER }}", + "recipients": "{{ .RECIPIENTS }}" +} +``` + +**Query** + +``` +http://.../?@number={{.NUMBER}} +``` + +**Path** + +``` +http://signal-api:8880/v1/receive/{{.NUMBER}} +``` + +#### KeyValue Pair Injection + +In some cases you may not be able to access / modify the Request Body, if that is the case specify needed values in the Requests Query: + +``` +http://signal-api:8880/?@key=value ``` -Which are blocked by default to increase Security, but you these can be modified by setting the `BLOCKED_ENDPOINTS` environment variable as a valid json array +**Format** +In order to differentiate Injection Queries and _regular_ Queries +you have to add `@` in front of any KeyValue Pair assignment + +### Environment Variables + +#### API Token + +> [!IMPORTANT] +> It is highly recommended to set this Environment Variable to a long secure string + +_What if I just don't?_ + +Well Secured Signal API will still work, but important Security Features won't be available +like Blocked Endpoints and anyone with access to your Docker Container will be able to send Messages in your Name + +> [!NOTE] +> Blocked Endpoints can be reactivated by manually setting them in the environment + +#### Blocked Endpoints + +Because Secured Signal API is just a secure Proxy you can use all of the [Signal REST API](https://github.com/bbernhard/signal-cli-rest-api/blob/master/doc/EXAMPLES.md) endpoints with an Exception of: + +- **/v1/about** + +- **/v1/configuration** + +- **/v1/devices** + +- **/v1/register** + +- **/v1/unregister** + +- **/v1/qrcodelink** + +- **/v1/accounts** + +- **/v1/contacts** + +These Endpoints are blocked by default to Security Risks, but can be modified by setting `BLOCKED_ENDPOINTS` in the environment variable to a valid json array string ```yaml environment: BLOCKED_ENDPOINTS: '[ "/v1/register","/v1/unregister","/v1/qrcodelink","/v1/contacts" ]' ``` +#### Variables + +By default Secured Signal API provides the following **Placeholders**: + +- **NUMBER** = _ENV_: `SENDER` +- **RECIPIENTS** = _ENV_: `DEFAULT_RECIPIENTS` + +If you are ever missing any **Placeholder** (that isn't built-in) you can add as many as you like to `VARIABLES` inside your environment + +```yaml +environment: + VARIABLES: ' "NUMBER2": "002", "GROUP_CHAT_1": [ "user.id", "000", "001", "group.id" ] ' +``` + +#### Default Recipients + +Set this environment variable to automatically provide default Recipients: + +```yaml +environment: + DEFAULT_RECIPIENTS: ' [ "user.id", "000", "001", "group.id" ] ' +``` + ## Contributing Found a bug? Want to change or add something? diff --git a/.github/workflows/docker-image-dev.yml b/.github/workflows/docker-image-dev.yml index 03e22920..82898542 100644 --- a/.github/workflows/docker-image-dev.yml +++ b/.github/workflows/docker-image-dev.yml @@ -9,7 +9,7 @@ on: jobs: update: - uses: codeshelldev/gh-actions/.github/workflows/docker-image.yml@main + uses: codeshelldev/gh-actions/.github/workflows/docker-image-go.yml@main with: registry: ghcr.io flavor: | diff --git a/Dockerfile b/Dockerfile index 7496a5c7..dde3acfa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,15 @@ -FROM golang:1.24 +FROM alpine:latest +RUN apk --no-cache add ca-certificates -WORKDIR /app - -COPY go.mod go.sum ./ - -RUN go mod download +ENV PORT=8880 -COPY *.go ./ +ARG TARGETOS +ARG TARGETARCH -RUN CGO_ENABLED=0 GOOS=linux go build -o /secured-signal-api +WORKDIR /app -ENV PORT=8880 +COPY dist/${TARGETOS}/${TARGETARCH}/app . -EXPOSE ${PORT} +RUN ls -CMD ["/secured-signal-api"] \ No newline at end of file +CMD ["./app"] \ No newline at end of file diff --git a/README.md b/README.md index 7e48462b..0926694c 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # Secured Signal Api -Secured Signal Api acts as a secured proxy for signal-rest-api. +Secured Signal Api acts as a secure proxy for signal-rest-api. ## Installation Get the latest version of the `docker-compose.yaml` file: +And set `API_TOKEN` to a long secure string + ```yaml --- services: @@ -33,6 +35,7 @@ services: SIGNAL_API_URL: http://signal-api:8080 DEFAULT_RECIPIENTS: '[ "000", "001", "002" ]' SENDER: 123456789 + API_TOKEN: LOOOOOONG_STRING ports: - "8880:8880" restart: unless-stopped @@ -60,6 +63,7 @@ services: SIGNAL_API_URL: http://signal-api:8080 DEFAULT_RECIPIENTS: '[ "000", "001", "002" ]' SENDER: 123456789 + API_TOKEN: LOOOOOONG_STRING labels: - traefik.enable=true - traefik.http.routers.signal-api.rule=Host(`signal-api.mydomain.com`) @@ -83,44 +87,149 @@ Before you can send messages via `secured-signal-api` you must first setup [`sig to send messages you have to either: -- register a Signal Account +- **register a Signal Account** OR -- link Signal Api to a already registered Signal Device +- **link Signal API to an already registered Signal Device** ## Usage +Secured Signal API implements 3 Ways to Authenticate + +### Bearer + +To Authenticate with `secured-signal-api` add `Authorization: Bearer TOKEN` to your request Headers + +### Basic Auth + +To use Basic Auth as Authorization Method add `Authorization: Basic base64{user:pw}` to your Headers + +### Query Auth + +If you are working with a limited Application you may **not** be able to modify Headers or the Request Body +in this case you should use **Query Auth**. + +Here is a simple example: + +```bash +curl -X POST http://signal-api:8880/v2/send?@authorization=TOKEN +``` + To send a message to `number`: `1234567`: ```bash curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer TOKEN" -d '{"message": "Hello World!", "recipients": ["1234567"]}' http://signal-api:8880/v2/send ``` -### Configuration - -Because `secured-signal-api` is just a secure proxy you can use all of the [Signal REST Api](https://github.com/bbernhard/signal-cli-rest-api/blob/master/doc/EXAMPLES.md) endpoints with an Exception of: - -```python -DEFAULT_BLOCKED_ENDPOINTS = [ - "/v1/about", - "/v1/configuration", - "/v1/devices", - "/v1/register", - "/v1/unregister", - "/v1/qrcodelink", - "/v1/accounts", - "/v1/contacts" -] +### Advanced + +#### Placeholders + +If you are not comfortable with hardcoding your Number and/or Recipients in you may use **Placeholders** in your request like: + +`{{ .NUMBER }}` or `{{ .RECIPIENTS }}` + +These _Placeholders_ can be used in the Query or the Body of a Request like so: + +**Body** + +```json +{ + "number": "{{ .NUMBER }}", + "recipients": "{{ .RECIPIENTS }}" +} +``` + +**Query** + +``` +http://.../?@number={{.NUMBER}} +``` + +**Path** + +``` +http://signal-api:8880/v1/receive/{{.NUMBER}} +``` + +#### KeyValue Pair Injection + +In some cases you may not be able to access / modify the Request Body, if that is the case specify needed values in the Requests Query: + +``` +http://signal-api:8880/?@key=value ``` -Which are blocked by default to increase Security, but you these can be modified by setting the `BLOCKED_ENDPOINTS` environment variable as a valid json array +**Format** +In order to differentiate Injection Queries and _regular_ Queries +you have to add `@` in front of any KeyValue Pair assignment + +### Environment Variables + +#### API Token + +> [!IMPORTANT] +> It is highly recommended to set this Environment Variable to a long secure string + +_What if I just don't?_ + +Well Secured Signal API will still work, but important Security Features won't be available +like Blocked Endpoints and anyone with access to your Docker Container will be able to send Messages in your Name + +> [!NOTE] +> Blocked Endpoints can be reactivated by manually setting them in the environment + +#### Blocked Endpoints + +Because Secured Signal API is just a secure Proxy you can use all of the [Signal REST API](https://github.com/bbernhard/signal-cli-rest-api/blob/master/doc/EXAMPLES.md) endpoints with an Exception of: + +- **/v1/about** + +- **/v1/configuration** + +- **/v1/devices** + +- **/v1/register** + +- **/v1/unregister** + +- **/v1/qrcodelink** + +- **/v1/accounts** + +- **/v1/contacts** + +These Endpoints are blocked by default to Security Risks, but can be modified by setting `BLOCKED_ENDPOINTS` in the environment variable to a valid json array string ```yaml environment: BLOCKED_ENDPOINTS: '[ "/v1/register","/v1/unregister","/v1/qrcodelink","/v1/contacts" ]' ``` +#### Variables + +By default Secured Signal API provides the following **Placeholders**: + +- **NUMBER** = _ENV_: `SENDER` +- **RECIPIENTS** = _ENV_: `DEFAULT_RECIPIENTS` + +If you are ever missing any **Placeholder** (that isn't built-in) you can add as many as you like to `VARIABLES` inside your environment + +```yaml +environment: + VARIABLES: ' "NUMBER2": "002", "GROUP_CHAT_1": [ "user.id", "000", "001", "group.id" ] ' +``` + +#### Default Recipients + +Set this environment variable to automatically provide default Recipients: + +```yaml +environment: + DEFAULT_RECIPIENTS: ' [ "user.id", "000", "001", "group.id" ] ' +``` + ## Contributing Found a bug? Want to change or add something? diff --git a/docker-compose.yaml b/docker-compose.yaml index 14fa642c..af56be4e 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -24,6 +24,7 @@ services: SIGNAL_API_URL: http://signal-api:8080 DEFAULT_RECIPIENTS: '[ "000", "001", "002" ]' SENDER: 123456789 + API_TOKEN: LOOOOOONG_STRING ports: - "8880:8880" restart: unless-stopped diff --git a/examples/traefik.docker-compose.yaml b/examples/traefik.docker-compose.yaml index 21d2bf25..67f680a1 100644 --- a/examples/traefik.docker-compose.yaml +++ b/examples/traefik.docker-compose.yaml @@ -12,6 +12,7 @@ services: SIGNAL_API_URL: http://signal-api:8080 DEFAULT_RECIPIENTS: '[ "000", "001", "002" ]' SENDER: 123456789 + API_TOKEN: LOOOOOONG_STRING labels: - traefik.enable=true - traefik.http.routers.signal-api.rule=Host(`signal-api.mydomain.com`) diff --git a/internals/proxy/proxy.go b/internals/proxy/proxy.go index 435c3c86..8158e20a 100644 --- a/internals/proxy/proxy.go +++ b/internals/proxy/proxy.go @@ -3,16 +3,18 @@ package proxy import ( "bytes" "encoding/base64" + "encoding/json" "io" "net/http" "net/http/httputil" "net/url" - "os" + "regexp" "slices" + "strconv" "strings" "text/template" - log "github.com/codeshelldev/secured-signal-api/utils" + log "github.com/codeshelldev/secured-signal-api/utils/logger" ) type AuthType string @@ -21,9 +23,36 @@ const ( Bearer AuthType = "Bearer" Basic AuthType = "Basic" Query AuthType = "Query" - None AuthType = "" + None AuthType = "None" ) +func parseTypedQuery(values []string) interface{} { + var result interface{} + + raw := values[0] + + intValue, err := strconv.Atoi(raw) + + if strings.Contains(raw, ",") { + parts := strings.Split(raw, ",") + var list []interface{} + for _, part := range parts { + if intVal, err := strconv.Atoi(part); err == nil { + list = append(list, intVal) + } else { + list = append(list, part) + } + } + result = list + } else if err == nil { + result = intValue + } else { + result = raw + } + + return result +} + func getAuthType(str string) AuthType { switch str { case "Bearer": @@ -38,6 +67,8 @@ func getAuthType(str string) AuthType { func renderTemplate(name string, tmplStr string, data any) (string, error) { tmpl, err := template.New(name).Parse(tmplStr) + // TODO: Escape Arrays inside of strings "{{ .ARRAY }}" => [ 1, 2, 3 ] + if err != nil { return "", err } @@ -51,18 +82,58 @@ func renderTemplate(name string, tmplStr string, data any) (string, error) { return buf.String(), nil } -func AuthMiddleware(next http.Handler) http.Handler { +func templateJSON(data map[string]interface{}, variables map[string]interface{}) map[string]interface{} { + for k, v := range data { + str, ok := v.(string) + + if ok { + re, err := regexp.Compile(`{{\s*\.([A-Za-z_][A-Za-z0-9_]*)\s*}}`) + + if err != nil { + log.Error("Encountered Error while Compiling Regex: ", err.Error()) + } + + matches := re.FindAllStringSubmatch(str, -1) + + if len(matches) > 1 { + for i, tmplStr := range(matches) { + + tmplKey := matches[i][1] + + variable, err := json.Marshal(variables[tmplKey]) + + if err != nil { + log.Error("Could not decode JSON: ", err.Error()) + break + } + + data[k] = strings.ReplaceAll(str, string(variable), tmplStr[0]) + } + } else if len(matches) == 1 { + tmplKey := matches[0][1] + + data[k] = variables[tmplKey] + } + } + } + + return data +} + +func AuthMiddleware(next http.Handler, token string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - log.Info("Request:", req.Method, req.URL.Path) + if token == "" { + next.ServeHTTP(w, req) + return + } - token := os.Getenv("API_TOKEN") - user := "api" + log.Info("Request:", req.Method, req.URL.Path) authHeader := req.Header.Get("Authorization") - authQuery := req.URL.Query().Get("authorization") + authQuery := req.URL.Query().Get("@authorization") - var authType AuthType + var authType AuthType = None success := false @@ -88,6 +159,8 @@ func AuthMiddleware(next http.Handler) http.Handler { basicAuth := string(basicAuthBody) basicAuthParams := strings.Split(basicAuth, ":") + user := "api" + if basicAuthParams[0] == user && basicAuthParams[1] == token { success = true } @@ -100,10 +173,18 @@ func AuthMiddleware(next http.Handler) http.Handler { if authToken == token { success = true + + modifiedQuery := req.URL.Query() + + modifiedQuery.Del("@authorization") + + req.URL.RawQuery = modifiedQuery.Encode() } } if !success { + w.Header().Set("WWW-Authenticate", "Basic realm=\"Login Required\", Bearer realm=\"Access Token Required\"") + log.Warn("User failed ", string(authType), " Auth") http.Error(w, "Unauthorized", http.StatusUnauthorized) return @@ -127,28 +208,73 @@ func BlockedEndpointMiddleware(next http.Handler, BLOCKED_ENDPOINTS []string) ht }) } -func TemplatingMiddleware(next http.Handler, VARIABLES map[string]string) http.Handler { +func TemplatingMiddleware(next http.Handler, VARIABLES map[string]interface{}) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { if req.Body != nil { bodyBytes, err := io.ReadAll(req.Body) if err != nil { - log.Error("Could not decode Body: ", err.Error()) + log.Error("Could not read Body: ", err.Error()) http.Error(w, "Internal Error", http.StatusInternalServerError) return } req.Body.Close() - modifiedBody := string(bodyBytes) + var modifiedBodyData map[string]interface{} + + err = json.Unmarshal(bodyBytes, &modifiedBodyData) + + if err != nil { + log.Error("Could not decode Body: ", err.Error()) + http.Error(w, "Internal Error", http.StatusInternalServerError) + return + } + + modifiedBodyData = templateJSON(modifiedBodyData, VARIABLES) + + if req.URL.RawQuery != "" { + query, _ := renderTemplate("query", req.URL.RawQuery, VARIABLES) + + modifiedQuery := req.URL.Query() - modifiedBody, _ = renderTemplate("json", modifiedBody, VARIABLES) - modifiedBodyBytes := []byte(modifiedBody) + queryData, _ := url.ParseQuery(query) + + for key, value := range queryData { + keyWithoutPrefix, found := strings.CutPrefix(key, "@") + + if found { + modifiedBodyData[keyWithoutPrefix] = parseTypedQuery(value) + + modifiedQuery.Del(key) + } + } + + req.URL.RawQuery = modifiedQuery.Encode() + + log.Debug("Applied Query Templating: ", query) + } + + modifiedBodyBytes, err := json.Marshal(modifiedBodyData) + + if err != nil { + log.Error("Could not encode Body: ", err.Error()) + http.Error(w, "Internal Error", http.StatusInternalServerError) + return + } + + modifiedBody := string(modifiedBodyBytes) + + log.Debug("Applied Body Templating: ", modifiedBody) req.Body = io.NopCloser(bytes.NewReader(modifiedBodyBytes)) + + req.ContentLength = int64(len(modifiedBody)) + req.Header.Set("Content-Length", strconv.Itoa(len(modifiedBody))) } reqPath := req.URL.Path + reqPath, _ = url.PathUnescape(reqPath) modifiedReqPath, _ := renderTemplate("path", reqPath, VARIABLES) diff --git a/main.go b/main.go index ab08c114..60efb52a 100644 --- a/main.go +++ b/main.go @@ -1,63 +1,42 @@ package main import ( - "encoding/json" "net/http" "net/http/httputil" "os" proxy "github.com/codeshelldev/secured-signal-api/internals/proxy" - log "github.com/codeshelldev/secured-signal-api/utils" + env "github.com/codeshelldev/secured-signal-api/utils/env" + log "github.com/codeshelldev/secured-signal-api/utils/logger" ) var handler *httputil.ReverseProxy -var VARIABLES map[string]string = map[string]string{ - "RECIPIENTS": os.Getenv("DEFAULT_RECIPIENTS"), - "NUMBER": os.Getenv("SENDER"), -} - -var BLOCKED_ENDPOINTS []string = []string{ - "/v1/about", - "/v1/configuration", - "/v1/devices", - "/v1/register", - "/v1/unregister", - "/v1/qrcodelink", - "/v1/accounts", - "/v1/contacts", -} +var ENV env.ENV_ func main() { logLevel := os.Getenv("LOG_LEVEL") log.Init(logLevel) - port := os.Getenv("PORT") - signalUrl := os.Getenv("SIGNAL_API_URL") + env.Load() - blockedEndpointJSON := os.Getenv("BLOCKED_ENDPOINTS") + ENV = env.ENV - if blockedEndpointJSON != "" { - var blockedEndpoints []string + handler = proxy.Create(ENV.API_URL) - err := json.Unmarshal([]byte(blockedEndpointJSON), &blockedEndpoints) - - if err != nil { - log.Error("Could not decode Blocked Endpoints: ", blockedEndpointJSON) - } - - BLOCKED_ENDPOINTS = blockedEndpoints - } + finalHandler := proxy.AuthMiddleware( + proxy.BlockedEndpointMiddleware( + proxy.TemplatingMiddleware(handler, + ENV.VARIABLES ), + ENV.BLOCKED_ENDPOINTS ), + ENV.API_TOKEN ) - handler = proxy.Create(signalUrl) + log.Info("Initialized Proxy Handler") - finalHandler := proxy.TemplatingMiddleware( - proxy.BlockedEndpointMiddleware( - proxy.AuthMiddleware(handler), + addr := "0.0.0.0:" + ENV.PORT - BLOCKED_ENDPOINTS), - VARIABLES) + log.Info("Server Listening on ", addr) - http.ListenAndServe("0.0.0.0:" + port, finalHandler) + http.ListenAndServe(addr, finalHandler) } \ No newline at end of file diff --git a/utils/env/env.go b/utils/env/env.go new file mode 100644 index 00000000..648a0de8 --- /dev/null +++ b/utils/env/env.go @@ -0,0 +1,90 @@ +package env + +import ( + "encoding/json" + "os" + + log "github.com/codeshelldev/secured-signal-api/utils/logger" +) + +type ENV_ struct { + PORT string + API_URL string + API_TOKEN string + BLOCKED_ENDPOINTS []string + VARIABLES map[string]any +} + +var ENV ENV_ = ENV_{ + BLOCKED_ENDPOINTS: []string { + "/v1/about", + "/v1/configuration", + "/v1/devices", + "/v1/register", + "/v1/unregister", + "/v1/qrcodelink", + "/v1/accounts", + "/v1/contacts", + }, + VARIABLES: map[string]any { + "RECIPIENTS": []string{}, + "NUMBER": os.Getenv("SENDER"), + }, +} + +func Load() { + ENV.PORT = os.Getenv("PORT") + ENV.API_URL = os.Getenv("SIGNAL_API_URL") + + ENV.API_TOKEN = os.Getenv("API_TOKEN") + + blockedEndpointJSON := os.Getenv("BLOCKED_ENDPOINTS") + recipientsJSON := os.Getenv("DEFAULT_RECIPIENTS") + variablesJSON := os.Getenv("VARIABLES") + + log.Info("Loaded Environment Variables") + + if ENV.API_TOKEN == "" { + log.Warn("No API TOKEN provided this is NOT recommended") + + log.Info("Disabling Security Features due to incomplete Congfiguration") + + ENV.BLOCKED_ENDPOINTS = []string{} + } + + if blockedEndpointJSON != "" { + var blockedEndpoints []string + + err := json.Unmarshal([]byte(blockedEndpointJSON), &blockedEndpoints) + + if err != nil { + log.Error("Could not decode Blocked Endpoints: ", blockedEndpointJSON) + } + + ENV.BLOCKED_ENDPOINTS = blockedEndpoints + } + + if variablesJSON != "" { + var variables map[string]interface{} + + err := json.Unmarshal([]byte(variablesJSON), &variables) + + if err != nil { + log.Error("Could not decode Variables ", variablesJSON) + } + + ENV.VARIABLES = variables + } + + if recipientsJSON != "" { + var recipients []string + + err := json.Unmarshal([]byte(recipientsJSON), &recipients) + + if err != nil { + log.Error("Could not decode Variables ", variablesJSON) + } + + ENV.VARIABLES["RECIPIENTS"] = recipients + } +} \ No newline at end of file diff --git a/utils/logger.go b/utils/logger/logger.go similarity index 81% rename from utils/logger.go rename to utils/logger/logger.go index b145cadf..77ab5634 100644 --- a/utils/logger.go +++ b/utils/logger/logger.go @@ -1,13 +1,14 @@ package logger import ( + "fmt" "strings" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) -var log *zap.Logger +var _log *zap.Logger func Init(level string) { logLevel := getLogLevel(level) @@ -36,10 +37,10 @@ func Init(level string) { var err error - log, err = cfg.Build(zap.AddCaller(), zap.AddCallerSkip(1)) + _log, err = cfg.Build(zap.AddCaller(), zap.AddCallerSkip(1)) if err != nil { - panic(err) + fmt.Println("Encountered Error during Log.Init(): err.Error()") } Info("Initialized Logger with Level of", logLevel.String()) @@ -61,22 +62,22 @@ func getLogLevel(level string) zapcore.Level { } func Info(msg ...string) { - log.Info(strings.Join(msg, " ")) + _log.Info(strings.Join(msg, " ")) } func Debug(msg ...string) { - log.Debug(strings.Join(msg, " ")) + _log.Debug(strings.Join(msg, " ")) } func Error(msg ...string) { - log.Error(strings.Join(msg, " ")) + _log.Error(strings.Join(msg, " ")) } func Warn(msg ...string) { - log.Warn(strings.Join(msg, " ")) + _log.Warn(strings.Join(msg, " ")) } func Sync() { - _ = log.Sync() + _ = _log.Sync() } \ No newline at end of file