diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..e32b7d4 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,60 @@ +name: Build and run docker image on remote +on: + create: + tags: + - v* + +jobs: + push: + name: Push Docker image + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Log in to Docker Hub + uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + images: | + jekabolt/grbpwr-manager + + - name: Build and push Docker images + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + deploy: + runs-on: ubuntu-latest + needs: push + steps: + - uses: actions/checkout@v2 + - name: Set env + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + - name: executing remote ssh commands using ssh key + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.SSH_HOST }} + username: ${{ secrets.SSH_USER }} + key: ${{ secrets.ID_RSA }} + script: | + docker pull jekabolt/grbpwr-manager:${{ env.RELEASE_VERSION }} + docker stop grbpwr-manager + docker rm grbpwr-manager + docker run --name=grbpwr-manager -d \ + --restart=unless-stopped \ + --publish 8001:8001 \ + --env-file /root/env/.env \ + --mount src=/root/bunt,target=/root/bunt,type=bind \ + jekabolt/grbpwr-manager:${{ env.RELEASE_VERSION }} diff --git a/art-admin/.gitignore b/art-admin/.gitignore index d51d9a4..93adfed 100644 --- a/art-admin/.gitignore +++ b/art-admin/.gitignore @@ -1,6 +1,6 @@ # See http://help.github.com/ignore-files/ for more about ignoring files. -.vscode +*vscode art-admin .env *.db diff --git a/art-admin/Dockerfile b/art-admin/Dockerfile new file mode 100644 index 0000000..db08a38 --- /dev/null +++ b/art-admin/Dockerfile @@ -0,0 +1,21 @@ +FROM golang:1-alpine AS development + +ENV PROJECT_PATH=/art-admin +ENV PATH=$PATH:$PROJECT_PATH/bin + +RUN apk add --no-cache make git bash alpine-sdk protobuf + +RUN mkdir -p $PROJECT_PATH +COPY . $PROJECT_PATH +WORKDIR $PROJECT_PATH + +RUN make install clean build + +FROM alpine:latest AS production + +WORKDIR /root/ +RUN apk --no-cache add ca-certificates + +COPY --from=development /art-admin/bin/ art-admin +RUN ["chmod", "+x", "./art-admin"] +ENTRYPOINT ["./art-admin"] diff --git a/art-admin/Makefile b/art-admin/Makefile index 1c6f29c..7204541 100644 --- a/art-admin/Makefile +++ b/art-admin/Makefile @@ -3,7 +3,7 @@ IMAGE_NAME=art-admin VERSION=master build: statics - go build -o ./bin/$(IMAGE_NAME) ./cmd/ + go build -a $(GO_EXTRA_BUILD_ARGS) -ldflags "-s -w -X main.version=$(VERSION)" -o ./bin/$(IMAGE_NAME) ./cmd/ run: build ./bin/$(IMAGE_NAME) @@ -16,12 +16,12 @@ coverage: local: build source .env && ./bin/$(IMAGE_NAME) -image: - docker build -t $(REGISTRY)/${IMAGE_NAME}:$(VERSION) . +# image: +# docker build -t $(REGISTRY)/${IMAGE_NAME}:$(VERSION) . -image-run: - docker run --publish 8081:8081 --env-file .env \ - --mount src=/root/bunt,target=/root/bunt,type=bind \$(REGISTRY)/${IMAGE_NAME}:$(VERSION) +# image-run: +# docker run --publish 8081:8081 --env-file .env \ +# --mount src=/root/bunt,target=/root/bunt,type=bind \$(REGISTRY)/${IMAGE_NAME}:$(VERSION) generate: buf generate --path ./proto/nft/nft.proto \ @@ -46,4 +46,32 @@ install: go install github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway@latest go install github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger@latest go install github.com/go-bindata/go-bindata/go-bindata@latest - go install golang.org/x/text/cmd/gotext@latest \ No newline at end of file + go install golang.org/x/text/cmd/gotext@latest + + +# configuration for image names +BUILD_TYPE := dev # for the autobuilds will be "release" + +VERSION_CURRENT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD) +VERSION_CURRENT_DATE := $(shell date +'%Y.%m.%d') +VERSION_GIT_COMMIT := $(shell git rev-parse --short HEAD) +VERSION_BUILD_NUMBER := $(shell git rev-list --count HEAD) +VERSION_TAG_LONG := v_._._-$(VERSION_BUILD_NUMBER:-=)-$(VERSION_GIT_COMMIT) + +GIT_TAG := $(shell git describe 2>/dev/null) +ifeq ($(GIT_TAG),) + GIT_TAG := $(VERSION_TAG_LONG) +endif + +IMAGE_VERSION := $(shell printf '%s-%s-%s' $(GIT_TAG) $(VERSION_CURRENT_DATE) $(VERSION_CURRENT_BRANCH) ) + + +# configuration for binary and image +IMAGE_NAME := bot-detection-tool +IMAGE_DOCKERFILE := $(DOCKERFILE_PATH)/Dockerfile +DOCKER_IMAGE := $(REGISTRY)/$(IMAGE_NAME):$(IMAGE_VERSION) + +image-build: ## build the docker image + docker build \ + --progress=plain \ + -t $(DOCKER_IMAGE) . \ No newline at end of file diff --git a/art-admin/app/auth/auth.go b/art-admin/app/auth/auth.go index 6ba1db1..2580d16 100644 --- a/art-admin/app/auth/auth.go +++ b/art-admin/app/auth/auth.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "strings" + "time" "github.com/go-chi/jwtauth/v5" @@ -18,6 +19,7 @@ type Server struct { pb_auth.UnimplementedAuthServer pwhash *pwhash.PasswordHasher jwtAuth *jwtauth.JWTAuth + jwtTTL time.Duration c *Config AdminPasswordHash string } @@ -27,11 +29,15 @@ type Config struct { AdminPassword string `env:"AUTH_ADMIN_PASSWORD" envDefault:"hehe"` PasswordHasherSaltSize int `env:"AUTH_PASSWORD_HASHER_SALT" envDefault:"16"` PasswordHasherIterations int `env:"AUTH_PASSWORD_HASHER_ITERATIONS" envDefault:"100000"` - JWTTTL int `env:"AUTH_JWT_TTL" envDefault:"60"` // in minutes + JWTTTL string `env:"AUTH_JWT_TTL" envDefault:"60m"` // in minutes } // New creates a new auth server. func (c *Config) New() (*Server, error) { + ttl, err := time.ParseDuration(c.JWTTTL) + if err != nil && c.JWTTTL != "" { + return nil, fmt.Errorf("bad duration for ttl [%s] - %v", c.JWTTTL, err.Error()) + } phasher, err := pwhash.New(c.PasswordHasherSaltSize, c.PasswordHasherIterations) if err != nil { return nil, fmt.Errorf("cannot create password hasher: %v", err) @@ -43,6 +49,7 @@ func (c *Config) New() (*Server, error) { s := &Server{ pwhash: phasher, jwtAuth: jwtauth.New("HS256", []byte(c.JWTSecret), nil), + jwtTTL: ttl, c: c, AdminPasswordHash: adminPwHash, } @@ -56,7 +63,7 @@ func (s *Server) Login(ctx context.Context, req *pb_auth.LoginRequest) (*pb_auth return nil, fmt.Errorf("cannot validate password: %s", err.Error()) } - token, err := jwt.NewToken(s.jwtAuth, s.c.JWTTTL) + token, err := jwt.NewToken(s.jwtAuth, s.jwtTTL) if err != nil { return nil, fmt.Errorf("cannot create token: %s", err.Error()) } diff --git a/art-admin/app/auth/auth_test.go b/art-admin/app/auth/auth_test.go index a10c57b..aee5d29 100644 --- a/art-admin/app/auth/auth_test.go +++ b/art-admin/app/auth/auth_test.go @@ -26,7 +26,7 @@ func TestAuth(t *testing.T) { AdminPassword: AdminPassword, PasswordHasherSaltSize: 16, PasswordHasherIterations: 100000, - JWTTTL: 60, + JWTTTL: "60m", } authSrv, err := c.New() is.NoErr(err) diff --git a/art-admin/auth/jwt/jwtauth.go b/art-admin/auth/jwt/jwtauth.go index 8c7d3ac..37efd3d 100644 --- a/art-admin/auth/jwt/jwtauth.go +++ b/art-admin/auth/jwt/jwtauth.go @@ -14,10 +14,9 @@ func VerifyToken(jwtAuth *jwtauth.JWTAuth, token string) (string, error) { return t.Subject(), nil } -func NewToken(jwtAuth *jwtauth.JWTAuth, ttl int) (string, error) { +func NewToken(jwtAuth *jwtauth.JWTAuth, ttl time.Duration) (string, error) { _, ts, err := jwtAuth.Encode(map[string]interface{}{ - "exp": time.Now().Add((time.Minute) * - time.Duration(ttl)).Unix(), + "exp": time.Now().Add(ttl).Unix(), }) if err != nil { return ts, err diff --git a/art-admin/bucket/bucket.go b/art-admin/bucket/bucket.go index f4c716f..646d27f 100644 --- a/art-admin/bucket/bucket.go +++ b/art-admin/bucket/bucket.go @@ -11,9 +11,9 @@ type Config struct { S3BucketName string `env:"S3_BUCKET_NAME" envDefault:"grbpwr"` S3BucketLocation string `env:"S3_BUCKET_LOCATION" envDefault:"fra-1"` BaseFolder string `env:"S3_BASE_FOLDER" envDefault:"solutions"` - ImageStorePrefix string `env:"IMAGE_STORE_PREFIX" envDefault:"grbpwr-com"` - MetadataStorePrefix string `env:"METADATA_STORE_PREFIX" envDefault:"metadata"` - IPFSStoragePath string `env:"IPFS_STORAGE_PATH" envDefault:""` + ImageStorePrefix string `env:"S3_IMAGE_STORE_PREFIX" envDefault:"grbpwr-com"` + MetadataStorePrefix string `env:"S3_METADATA_STORE_PREFIX" envDefault:"metadata"` + IPFSStoragePath string `env:"S3_IPFS_STORAGE_PATH" envDefault:""` } type FileStore interface { diff --git a/art-admin/config/cfg.go b/art-admin/config/cfg.go index e81245e..bb8ad4f 100644 --- a/art-admin/config/cfg.go +++ b/art-admin/config/cfg.go @@ -15,9 +15,6 @@ import ( ) type Config struct { - Port string `env:"PORT" envDefault:"8081"` - Hosts []string `env:"HOSTS" envSeparator:"|"` - Bunt *bunt.Config Bucket *bucket.Config Etherscan *eth.Config diff --git a/art-admin/eth/eth.go b/art-admin/eth/eth.go index 30f67cb..756e5cd 100644 --- a/art-admin/eth/eth.go +++ b/art-admin/eth/eth.go @@ -11,10 +11,10 @@ import ( ) type Config struct { - APIKey string `env:"ETHERSCAN_API_KEY"` - Network string `env:"ETHERSCAN_NETWORK" envDefault:"api-rinkeby"` - ContractAddress string `env:"CONTRACT_ADDRESS"` - RefreshTime string `env:"REFRESH_TIME" envDefault:"10m"` + APIKey string `env:"ETH_ETHERSCAN_API_KEY"` + Network string `env:"ETH_ETHERSCAN_NETWORK" envDefault:"api-rinkeby"` + ContractAddress string `env:"ETH_CONTRACT_ADDRESS"` + RefreshTime string `env:"ETH_REFRESH_TIME" envDefault:"10m"` } type ETHCli interface {