diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 0000000..e8f4851 --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,28 @@ +name: Collect Code Coverage + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build: + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: "1.20" + - name: Go Generate + run: go generate + - name: Run coverage + run: go test -race -failfast -coverprofile=coverage.txt -covermode=atomic -v ./... + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 diff --git a/.github/workflows/publish_npm.yml b/.github/workflows/publish_npm.yml new file mode 100644 index 0000000..91db9f4 --- /dev/null +++ b/.github/workflows/publish_npm.yml @@ -0,0 +1,38 @@ +name: publish npm + +on: + push: + tags: + - v*.*.* + workflow_dispatch: + +permissions: + contents: write + +jobs: + publish-npm: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 16 + registry-url: https://registry.npmjs.org/ + - name: Get version + id: get_version + run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} + - name: Set version + run: | + apt install jq + jq '.version="${{ steps.get_version.outputs.VERSION }}"' package.json > package.json.new + mv package.json.new package.json + - name: Generate SDK + run: | + npm cache clean --force + npm install @openapitools/openapi-generator-cli -g + make build + - run: npm i + - run: npm run start + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} \ No newline at end of file diff --git a/.github/workflows/push_test_server.yml b/.github/workflows/push_test_server.yml new file mode 100644 index 0000000..4cdfa56 --- /dev/null +++ b/.github/workflows/push_test_server.yml @@ -0,0 +1,75 @@ +name: Auto Publish Website +on: + push: + branches: + - main +permissions: + contents: write +jobs: + goreleaser: + runs-on: ubuntu-22.04 + steps: + - + name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: isntall git + run: sudo apt install --yes git + - name: git global + run: sudo git config --global --add safe.directory '*' + - + name: Fetch all tags + run: sudo git fetch --force --tags + + - name: set version + run: sudo git tag v99.99.99-alpha + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: 'stable' + + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v4 + with: + # either 'goreleaser' (default) or 'goreleaser-pro' + distribution: goreleaser + version: 1.14.1 + args: release --rm-dist --snapshot + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Your GoReleaser Pro key, if you are using the 'goreleaser-pro' distribution + # GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} + + - name: remove migration file + run: find . -type f \( -name '*migration*' \) -delete + + - name: install sshpass + run: sudo apt install sshpass --yes + + - name: ZeroTier + uses: zerotier/github-action@v1.0.1 + with: + network_id: ${{ secrets.ZEROTIER_NETWORK_ID }} + auth_token: ${{ secrets.ZEROTIER_CENTRAL_TOKEN }} + + - name: ping host + shell: bash + run: | + count=10 + while ! ping -c 1 10.147.18.11 ; do + echo "waiting..." ; + sleep 1 ; + let count=count-1 + done + echo "ping success" + + - name: copy tar to target host + shell: bash + run: | + sshpass -p "${{ secrets.ssh_password }}" scp -r -o StrictHostKeyChecking=no -P 22 ./dist/*.gz root@10.147.18.11:/var/www/download + echo "ping success" + - name: send message + run: | + curl -X POST -H "Content-Type: application/json" -d '{"msg_type":"text","content":{"text":"CasaOS-User updated"}}' ${{ secrets.SSH_ROBOT_URL }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..a1829c3 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,17 @@ +name: goreleaser + +on: + push: + tags: + - v*.*.* +permissions: + contents: write +jobs: + call-workflow-passing-data: + uses: IceWhaleTech/github/.github/workflows/go_release.yml@main + with: + project-name: CasaOS-UserService + file-name: casaos-user-service + secrets: + OSS_KEY_ID: ${{ secrets.OSS_KEY_ID }} + OSS_KEY_SECRET: ${{ secrets.OSS_KEY_SECRET }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bbd1446 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# IDE +.vscode/ +target/ +dist/ +__debug_bin +codegen/ + +node_modules/ +dist/ +.idea +.package-lock.json \ No newline at end of file diff --git a/.goreleaser.debug.yaml b/.goreleaser.debug.yaml index 5d80e56..dafcc4d 100644 --- a/.goreleaser.debug.yaml +++ b/.goreleaser.debug.yaml @@ -118,6 +118,8 @@ archives: - casaos-user-service-amd64 - casaos-user-service-arm64 - casaos-user-service-arm-7 + replacements: + arm: arm-7 files: - build/**/* - name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-migration-tool-v{{ .Version }}" @@ -126,6 +128,8 @@ archives: - casaos-user-service-migration-tool-amd64 - casaos-user-service-migration-tool-arm64 - casaos-user-service-migration-tool-arm-7 + replacements: + arm: arm-7 files: - build/sysroot/etc/**/* checksum: diff --git a/README.md b/README.md index 42e5d9c..7379f01 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CasaOS-UserService -[![Go Reference](https://pkg.go.dev/badge/github.com/KaySar12/NextZen-UserService.svg)](https://pkg.go.dev/github.com/KaySar12/NextZen-UserService) [![Go Report Card](https://goreportcard.com/badge/github.com/KaySar12/NextZen-UserService)](https://goreportcard.com/report/github.com/KaySar12/NextZen-UserService) [![goreleaser](https://github.com/KaySar12/NextZen-UserService/actions/workflows/release.yml/badge.svg)](https://github.com/KaySar12/NextZen-UserService/actions/workflows/release.yml) [![codecov](https://codecov.io/gh/IceWhaleTech/CasaOS-UserService/branch/main/graph/badge.svg?token=4GWJIF6FDD)](https://codecov.io/gh/IceWhaleTech/CasaOS-UserService) +[![Go Reference](https://pkg.go.dev/badge/github.com/IceWhaleTech/CasaOS-UserService.svg)](https://pkg.go.dev/github.com/IceWhaleTech/CasaOS-UserService) [![Go Report Card](https://goreportcard.com/badge/github.com/IceWhaleTech/CasaOS-UserService)](https://goreportcard.com/report/github.com/IceWhaleTech/CasaOS-UserService) [![goreleaser](https://github.com/IceWhaleTech/CasaOS-UserService/actions/workflows/release.yml/badge.svg)](https://github.com/IceWhaleTech/CasaOS-UserService/actions/workflows/release.yml) [![codecov](https://codecov.io/gh/IceWhaleTech/CasaOS-UserService/branch/main/graph/badge.svg?token=4GWJIF6FDD)](https://codecov.io/gh/IceWhaleTech/CasaOS-UserService) User Service provides user management functionalities to CasaOS. diff --git a/build/scripts/setup/service.d/user-service/debian/bullseye/setup-user-service.sh b/build/scripts/setup/service.d/user-service/debian/bullseye/setup-user-service.sh new file mode 120000 index 0000000..d1f69f2 --- /dev/null +++ b/build/scripts/setup/service.d/user-service/debian/bullseye/setup-user-service.sh @@ -0,0 +1 @@ +../setup-user-service.sh \ No newline at end of file diff --git a/build/scripts/setup/service.d/user-service/debian/setup-user-service.sh b/build/scripts/setup/service.d/user-service/debian/setup-user-service.sh new file mode 100644 index 0000000..86e7b09 --- /dev/null +++ b/build/scripts/setup/service.d/user-service/debian/setup-user-service.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +set -e + +readonly APP_NAME="casaos-user-service" +readonly APP_NAME_SHORT="user-service" + +# copy config files +readonly CONF_PATH=/etc/casaos +readonly CONF_FILE=${CONF_PATH}/${APP_NAME_SHORT}.conf +readonly CONF_FILE_SAMPLE=${CONF_PATH}/${APP_NAME_SHORT}.conf.sample + +if [ ! -f "${CONF_FILE}" ]; then \ + echo "Initializing config file..." + cp -v "${CONF_FILE_SAMPLE}" "${CONF_FILE}"; \ +fi + +systemctl daemon-reload + +# enable service (without starting) +echo "Enabling service..." +systemctl enable --force --no-ask-password "${APP_NAME}.service" diff --git a/build/scripts/setup/service.d/user-service/ubuntu/jammy/setup-user-service.sh b/build/scripts/setup/service.d/user-service/ubuntu/jammy/setup-user-service.sh new file mode 120000 index 0000000..d1f69f2 --- /dev/null +++ b/build/scripts/setup/service.d/user-service/ubuntu/jammy/setup-user-service.sh @@ -0,0 +1 @@ +../setup-user-service.sh \ No newline at end of file diff --git a/build/scripts/setup/service.d/user-service/ubuntu/setup-user-service.sh b/build/scripts/setup/service.d/user-service/ubuntu/setup-user-service.sh new file mode 120000 index 0000000..79d764b --- /dev/null +++ b/build/scripts/setup/service.d/user-service/ubuntu/setup-user-service.sh @@ -0,0 +1 @@ +../debian/setup-user-service.sh \ No newline at end of file diff --git a/build/sysroot/usr/share/casaos/cleanup/script.d/02-cleanup-user-service.sh b/build/sysroot/usr/share/casaos/cleanup/script.d/02-cleanup-user-service.sh new file mode 100755 index 0000000..ddd754c --- /dev/null +++ b/build/sysroot/usr/share/casaos/cleanup/script.d/02-cleanup-user-service.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +set -e + +readonly APP_NAME_SHORT=user-service + +__get_setup_script_directory_by_os_release() { + pushd "$(dirname "${BASH_SOURCE[0]}")/../service.d/${APP_NAME_SHORT}" &>/dev/null + + { + # shellcheck source=/dev/null + { + source /etc/os-release + { + pushd "${ID}"/"${VERSION_CODENAME}" &>/dev/null + } || { + pushd "${ID}" &>/dev/null + } || { + [[ -n ${ID_LIKE} ]] && for ID in ${ID_LIKE}; do + pushd "${ID}" >/dev/null && break + done + } || { + echo "Unsupported OS: ${ID} ${VERSION_CODENAME} (${ID_LIKE})" + exit 1 + } + + pwd + + popd &>/dev/null + + } || { + echo "Unsupported OS: unknown" + exit 1 + } + + } + + popd &>/dev/null +} + +SETUP_SCRIPT_DIRECTORY=$(__get_setup_script_directory_by_os_release) + +readonly SETUP_SCRIPT_DIRECTORY +readonly SETUP_SCRIPT_FILENAME="cleanup-${APP_NAME_SHORT}.sh" +readonly SETUP_SCRIPT_FILEPATH="${SETUP_SCRIPT_DIRECTORY}/${SETUP_SCRIPT_FILENAME}" + +echo "🟩 Running ${SETUP_SCRIPT_FILENAME}..." +$BASH "${SETUP_SCRIPT_FILEPATH}" "${BUILD_PATH}" diff --git a/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/arch/cleanup-user-service.sh b/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/arch/cleanup-user-service.sh new file mode 100644 index 0000000..f39f4ad --- /dev/null +++ b/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/arch/cleanup-user-service.sh @@ -0,0 +1,109 @@ +#!/bin/bash + +set -e + +readonly CASA_EXEC=casaos-user-service +readonly CASA_SERVICE=casaos-user-service.service + +CASA_SERVICE_PATH=$(systemctl show ${CASA_SERVICE} --no-pager --property FragmentPath | cut -d'=' -sf2) +readonly CASA_SERVICE_PATH + +CASA_CONF=$( grep -i ExecStart= "${CASA_SERVICE_PATH}" | cut -d'=' -sf2 | cut -d' ' -sf3) +if [[ -z "${CASA_CONF}" ]]; then + CASA_CONF=/etc/casaos/user-service.conf +fi + +CASA_DB_PATH=$( (grep -i dbpath "${CASA_CONF}" || echo "/var/lib/casaos/db") | cut -d'=' -sf2 | xargs ) +readonly CASA_DB_PATH + +CASA_DB_FILE=${CASA_DB_PATH}/user-service.db + +readonly aCOLOUR=( + '\e[38;5;154m' # green | Lines, bullets and separators + '\e[1m' # Bold white | Main descriptions + '\e[90m' # Grey | Credits + '\e[91m' # Red | Update notifications Alert + '\e[33m' # Yellow | Emphasis +) + +Show() { + # OK + if (($1 == 0)); then + echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[0]} OK $COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2" + # FAILED + elif (($1 == 1)); then + echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[3]}FAILED$COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2" + # INFO + elif (($1 == 2)); then + echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[0]} INFO $COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2" + # NOTICE + elif (($1 == 3)); then + echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[4]}NOTICE$COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2" + fi +} + +Warn() { + echo -e "${aCOLOUR[3]}$1$COLOUR_RESET" +} + +trap 'onCtrlC' INT +onCtrlC() { + echo -e "${COLOUR_RESET}" + exit 1 +} + +if [[ ! -x "$(command -v ${CASA_EXEC})" ]]; then + Show 2 "${CASA_EXEC} is not detected, exit the script." + exit 1 +fi + +while true; do + echo -n -e " ${aCOLOUR[4]}Do you want delete user database? Y/n :${COLOUR_RESET}" + read -r input + case $input in + [yY][eE][sS] | [yY]) + REMOVE_USER_DATABASE=true + break + ;; + [nN][oO] | [nN]) + REMOVE_USER_DATABASE=false + break + ;; + *) + echo -e " ${aCOLOUR[3]}Invalid input, please try again.${COLOUR_RESET}" + ;; + esac +done + +while true; do + echo -n -e " ${aCOLOUR[4]}Do you want delete user directory? Y/n :${COLOUR_RESET}" + read -r input + case $input in + [yY][eE][sS] | [yY]) + REMOVE_USER_DIRECTORY=true + break + ;; + [nN][oO] | [nN]) + REMOVE_USER_DIRECTORY=false + break + ;; + *) + echo -e " ${aCOLOUR[3]}Invalid input, please try again.${COLOUR_RESET}" + ;; + esac +done + +Show 2 "Stopping ${CASA_SERVICE}..." +systemctl disable --now "${CASA_SERVICE}" || Show 3 "Failed to disable ${CASA_SERVICE}" + +rm -rvf "$(which ${CASA_EXEC})" || Show 3 "Failed to remove ${CASA_EXEC}" +rm -rvf "${CASA_CONF}" || Show 3 "Failed to remove ${CASA_CONF}" + +if [[ "${REMOVE_USER_DATABASE}" == true ]]; then + rm -rvf "${CASA_DB_FILE}" || Show 3 "Failed to remove ${CASA_DB_FILE}" +fi + +if [[ "${REMOVE_USER_DIRECTORY}" == true ]]; then + Show 2 "Removing user directories..." + rm -rvf /var/lib/casaos/[1-9]* +fi diff --git a/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/debian/bullseye/cleanup-user-service.sh b/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/debian/bullseye/cleanup-user-service.sh new file mode 120000 index 0000000..4062f1d --- /dev/null +++ b/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/debian/bullseye/cleanup-user-service.sh @@ -0,0 +1 @@ +../cleanup-user-service.sh \ No newline at end of file diff --git a/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/debian/cleanup-user-service.sh b/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/debian/cleanup-user-service.sh new file mode 100644 index 0000000..f39f4ad --- /dev/null +++ b/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/debian/cleanup-user-service.sh @@ -0,0 +1,109 @@ +#!/bin/bash + +set -e + +readonly CASA_EXEC=casaos-user-service +readonly CASA_SERVICE=casaos-user-service.service + +CASA_SERVICE_PATH=$(systemctl show ${CASA_SERVICE} --no-pager --property FragmentPath | cut -d'=' -sf2) +readonly CASA_SERVICE_PATH + +CASA_CONF=$( grep -i ExecStart= "${CASA_SERVICE_PATH}" | cut -d'=' -sf2 | cut -d' ' -sf3) +if [[ -z "${CASA_CONF}" ]]; then + CASA_CONF=/etc/casaos/user-service.conf +fi + +CASA_DB_PATH=$( (grep -i dbpath "${CASA_CONF}" || echo "/var/lib/casaos/db") | cut -d'=' -sf2 | xargs ) +readonly CASA_DB_PATH + +CASA_DB_FILE=${CASA_DB_PATH}/user-service.db + +readonly aCOLOUR=( + '\e[38;5;154m' # green | Lines, bullets and separators + '\e[1m' # Bold white | Main descriptions + '\e[90m' # Grey | Credits + '\e[91m' # Red | Update notifications Alert + '\e[33m' # Yellow | Emphasis +) + +Show() { + # OK + if (($1 == 0)); then + echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[0]} OK $COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2" + # FAILED + elif (($1 == 1)); then + echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[3]}FAILED$COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2" + # INFO + elif (($1 == 2)); then + echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[0]} INFO $COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2" + # NOTICE + elif (($1 == 3)); then + echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[4]}NOTICE$COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2" + fi +} + +Warn() { + echo -e "${aCOLOUR[3]}$1$COLOUR_RESET" +} + +trap 'onCtrlC' INT +onCtrlC() { + echo -e "${COLOUR_RESET}" + exit 1 +} + +if [[ ! -x "$(command -v ${CASA_EXEC})" ]]; then + Show 2 "${CASA_EXEC} is not detected, exit the script." + exit 1 +fi + +while true; do + echo -n -e " ${aCOLOUR[4]}Do you want delete user database? Y/n :${COLOUR_RESET}" + read -r input + case $input in + [yY][eE][sS] | [yY]) + REMOVE_USER_DATABASE=true + break + ;; + [nN][oO] | [nN]) + REMOVE_USER_DATABASE=false + break + ;; + *) + echo -e " ${aCOLOUR[3]}Invalid input, please try again.${COLOUR_RESET}" + ;; + esac +done + +while true; do + echo -n -e " ${aCOLOUR[4]}Do you want delete user directory? Y/n :${COLOUR_RESET}" + read -r input + case $input in + [yY][eE][sS] | [yY]) + REMOVE_USER_DIRECTORY=true + break + ;; + [nN][oO] | [nN]) + REMOVE_USER_DIRECTORY=false + break + ;; + *) + echo -e " ${aCOLOUR[3]}Invalid input, please try again.${COLOUR_RESET}" + ;; + esac +done + +Show 2 "Stopping ${CASA_SERVICE}..." +systemctl disable --now "${CASA_SERVICE}" || Show 3 "Failed to disable ${CASA_SERVICE}" + +rm -rvf "$(which ${CASA_EXEC})" || Show 3 "Failed to remove ${CASA_EXEC}" +rm -rvf "${CASA_CONF}" || Show 3 "Failed to remove ${CASA_CONF}" + +if [[ "${REMOVE_USER_DATABASE}" == true ]]; then + rm -rvf "${CASA_DB_FILE}" || Show 3 "Failed to remove ${CASA_DB_FILE}" +fi + +if [[ "${REMOVE_USER_DIRECTORY}" == true ]]; then + Show 2 "Removing user directories..." + rm -rvf /var/lib/casaos/[1-9]* +fi diff --git a/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/ubuntu/cleanup-user-service.sh b/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/ubuntu/cleanup-user-service.sh new file mode 120000 index 0000000..3aeecd6 --- /dev/null +++ b/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/ubuntu/cleanup-user-service.sh @@ -0,0 +1 @@ +../debian/cleanup-user-service.sh \ No newline at end of file diff --git a/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/ubuntu/jammy/cleanup-user-service.sh b/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/ubuntu/jammy/cleanup-user-service.sh new file mode 120000 index 0000000..f1d1773 --- /dev/null +++ b/build/sysroot/usr/share/casaos/cleanup/service.d/user-service/ubuntu/jammy/cleanup-user-service.sh @@ -0,0 +1 @@ +../../debian/bullseye/cleanup-user-service.sh \ No newline at end of file diff --git a/cmd/migration-tool/main.go b/cmd/migration-tool/main.go index 33ca2bf..cbf1322 100644 --- a/cmd/migration-tool/main.go +++ b/cmd/migration-tool/main.go @@ -6,9 +6,9 @@ import ( "fmt" "os" - interfaces "github.com/KaySar12/NextZen-Common" - "github.com/KaySar12/NextZen-Common/utils/systemctl" - "github.com/KaySar12/NextZen-UserService/common" + interfaces "github.com/IceWhaleTech/CasaOS-Common" + "github.com/IceWhaleTech/CasaOS-Common/utils/systemctl" + "github.com/IceWhaleTech/CasaOS-UserService/common" ) const ( diff --git a/cmd/migration-tool/migration_dummy.go b/cmd/migration-tool/migration_dummy.go index 131976c..6d08df2 100644 --- a/cmd/migration-tool/migration_dummy.go +++ b/cmd/migration-tool/migration_dummy.go @@ -1,7 +1,7 @@ package main import ( - interfaces "github.com/KaySar12/NextZen-Common" + interfaces "github.com/IceWhaleTech/CasaOS-Common" ) type migrationTool struct{} diff --git a/common/version.go b/common/version.go index feb4161..619d87d 100644 --- a/common/version.go +++ b/common/version.go @@ -1,3 +1,4 @@ package common -const Version = "0.4.4" +const Version = "0.4.8" +const SERVICENAME = "CasaOS-UserService" diff --git a/go.mod b/go.mod index 5ac57d0..fe75d9f 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,9 @@ -module github.com/KaySar12/NextZen-UserService +module github.com/IceWhaleTech/CasaOS-UserService go 1.20 require ( - github.com/KaySar12/NextZen-Common v1.0.1 + github.com/IceWhaleTech/CasaOS-Common v0.4.8-alpha12 github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf github.com/deepmap/oapi-codegen v1.12.4 github.com/getkin/kin-openapi v0.117.0 @@ -15,6 +15,7 @@ require ( github.com/tidwall/gjson v1.14.4 go.uber.org/zap v1.24.0 golang.org/x/net v0.17.0 + golang.org/x/time v0.3.0 gopkg.in/ini.v1 v1.67.0 gorm.io/gorm v1.25.0 ) @@ -75,7 +76,6 @@ require ( golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect golang.org/x/sys v0.14.0 // indirect golang.org/x/text v0.13.0 // indirect - golang.org/x/time v0.3.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 34a3970..bc16b76 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/KaySar12/NextZen-Common v1.0.1 h1:w+QTKRmXJBmru3Ig4x142k6c7oD6ZTMF13Q0Fu19bGo= -github.com/KaySar12/NextZen-Common v1.0.1/go.mod h1:7AnhDlcVN9Dusql3aFy7y7TcyoKO3Pb9n/r0krTAWsw= +github.com/IceWhaleTech/CasaOS-Common v0.4.8-alpha12 h1:TikSpmsMOxKufqoq8Q4K3PLh8zIKFrRtLH4JDIG+910= +github.com/IceWhaleTech/CasaOS-Common v0.4.8-alpha12/go.mod h1:2IuYyy5qW1BE6jqC6M+tOU+WtUec1K565rLATBJ9p/0= github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= diff --git a/main.go b/main.go index 5c24d5b..5d886bf 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( + "context" _ "embed" "flag" "fmt" @@ -13,18 +14,19 @@ import ( "strings" "time" - "github.com/KaySar12/NextZen-Common/external" - "github.com/KaySar12/NextZen-Common/model" - util_http "github.com/KaySar12/NextZen-Common/utils/http" - "github.com/KaySar12/NextZen-Common/utils/jwt" - "github.com/KaySar12/NextZen-Common/utils/logger" - "github.com/KaySar12/NextZen-UserService/common" - "github.com/KaySar12/NextZen-UserService/pkg/config" - "github.com/KaySar12/NextZen-UserService/pkg/sqlite" - "github.com/KaySar12/NextZen-UserService/pkg/utils/encryption" - "github.com/KaySar12/NextZen-UserService/pkg/utils/random" - "github.com/KaySar12/NextZen-UserService/route" - "github.com/KaySar12/NextZen-UserService/service" + "github.com/IceWhaleTech/CasaOS-Common/external" + "github.com/IceWhaleTech/CasaOS-Common/model" + util_http "github.com/IceWhaleTech/CasaOS-Common/utils/http" + "github.com/IceWhaleTech/CasaOS-Common/utils/jwt" + "github.com/IceWhaleTech/CasaOS-Common/utils/logger" + "github.com/IceWhaleTech/CasaOS-UserService/codegen/message_bus" + "github.com/IceWhaleTech/CasaOS-UserService/common" + "github.com/IceWhaleTech/CasaOS-UserService/pkg/config" + "github.com/IceWhaleTech/CasaOS-UserService/pkg/sqlite" + "github.com/IceWhaleTech/CasaOS-UserService/pkg/utils/encryption" + "github.com/IceWhaleTech/CasaOS-UserService/pkg/utils/random" + "github.com/IceWhaleTech/CasaOS-UserService/route" + "github.com/IceWhaleTech/CasaOS-UserService/service" "github.com/coreos/go-systemd/daemon" "go.uber.org/zap" ) @@ -154,6 +156,23 @@ func main() { go route.EventListen() logger.Info("User service is listening...", zap.Any("address", listener.Addr().String()), zap.String("filepath", addressFilePath)) + var events []message_bus.EventType + events = append(events, message_bus.EventType{Name: "zimaos:user:save_config", SourceID: common.SERVICENAME, PropertyTypeList: []message_bus.PropertyType{}}) + // register at message bus + for i := 0; i < 10; i++ { + response, err := service.MyService.MessageBus().RegisterEventTypesWithResponse(context.Background(), events) + if err != nil { + logger.Error("error when trying to register one or more event types - some event type will not be discoverable", zap.Error(err)) + } + if response != nil && response.StatusCode() != http.StatusOK { + logger.Error("error when trying to register one or more event types - some event type will not be discoverable", zap.String("status", response.Status()), zap.String("body", string(response.Body))) + } + if response.StatusCode() == http.StatusOK { + break + } + time.Sleep(time.Second) + } + s := &http.Server{ Handler: mux, ReadHeaderTimeout: 5 * time.Second, // fix G112: Potential slowloris attack (see https://github.com/securego/gosec) diff --git a/package.json b/package.json index 6e4af21..8ce77a7 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "publish": "npm publish --access public", "start": "yarn generate:ts && yarn build" }, - "homepage": "https://github.com/KaySar12/NextZen-UserService#readme", + "homepage": "https://github.com/IceWhaleTech/CasaOS-UserService#readme", "description": "Casaos-Localstorage Typescript+Axios SDK", "keywords": [ "CasaOS-UserService", diff --git a/pkg/config/init.go b/pkg/config/init.go index b83998e..ac9b341 100644 --- a/pkg/config/init.go +++ b/pkg/config/init.go @@ -5,8 +5,8 @@ import ( "log" "os" - "github.com/KaySar12/NextZen-Common/utils/constants" - "github.com/KaySar12/NextZen-UserService/model" + "github.com/IceWhaleTech/CasaOS-Common/utils/constants" + "github.com/IceWhaleTech/CasaOS-UserService/model" "gopkg.in/ini.v1" ) diff --git a/pkg/sqlite/db.go b/pkg/sqlite/db.go index 9de31a7..331d64e 100644 --- a/pkg/sqlite/db.go +++ b/pkg/sqlite/db.go @@ -12,10 +12,10 @@ package sqlite import ( "time" - "github.com/KaySar12/NextZen-Common/utils/logger" - "github.com/KaySar12/NextZen-UserService/model" - "github.com/KaySar12/NextZen-UserService/pkg/utils/file" - model2 "github.com/KaySar12/NextZen-UserService/service/model" + "github.com/IceWhaleTech/CasaOS-Common/utils/logger" + "github.com/IceWhaleTech/CasaOS-UserService/model" + "github.com/IceWhaleTech/CasaOS-UserService/pkg/utils/file" + model2 "github.com/IceWhaleTech/CasaOS-UserService/service/model" "github.com/glebarez/sqlite" "go.uber.org/zap" "gorm.io/gorm" diff --git a/route/event_listen.go b/route/event_listen.go index 2e54696..a6e851b 100644 --- a/route/event_listen.go +++ b/route/event_listen.go @@ -7,12 +7,12 @@ import ( "strings" "time" - "github.com/KaySar12/NextZen-Common/external" - "github.com/KaySar12/NextZen-Common/utils/logger" - message_bus "github.com/KaySar12/NextZen-UserService/codegen/message_bus" - "github.com/KaySar12/NextZen-UserService/model" - "github.com/KaySar12/NextZen-UserService/pkg/config" - "github.com/KaySar12/NextZen-UserService/service" + "github.com/IceWhaleTech/CasaOS-Common/external" + "github.com/IceWhaleTech/CasaOS-Common/utils/logger" + message_bus "github.com/IceWhaleTech/CasaOS-UserService/codegen/message_bus" + "github.com/IceWhaleTech/CasaOS-UserService/model" + "github.com/IceWhaleTech/CasaOS-UserService/pkg/config" + "github.com/IceWhaleTech/CasaOS-UserService/service" "go.uber.org/zap" "golang.org/x/net/websocket" ) diff --git a/route/v1.go b/route/v1.go index 277f0b5..70df0a6 100644 --- a/route/v1.go +++ b/route/v1.go @@ -4,10 +4,10 @@ import ( "crypto/ecdsa" "os" - "github.com/KaySar12/NextZen-Common/middleware" - "github.com/KaySar12/NextZen-Common/utils/jwt" - v1 "github.com/KaySar12/NextZen-UserService/route/v1" - "github.com/KaySar12/NextZen-UserService/service" + "github.com/IceWhaleTech/CasaOS-Common/middleware" + "github.com/IceWhaleTech/CasaOS-Common/utils/jwt" + v1 "github.com/IceWhaleTech/CasaOS-UserService/route/v1" + "github.com/IceWhaleTech/CasaOS-UserService/service" "github.com/gin-contrib/gzip" "github.com/gin-gonic/gin" ) diff --git a/route/v1/user.go b/route/v1/user.go index 612a715..fcc2005 100644 --- a/route/v1/user.go +++ b/route/v1/user.go @@ -1,6 +1,7 @@ package v1 import ( + "context" "crypto/ecdsa" "encoding/base64" json2 "encoding/json" @@ -13,24 +14,28 @@ import ( "os" "path" "path/filepath" + "regexp" "strconv" "strings" "time" - "github.com/KaySar12/NextZen-Common/utils/common_err" - "github.com/KaySar12/NextZen-Common/utils/jwt" - "github.com/KaySar12/NextZen-Common/utils/logger" - "github.com/KaySar12/NextZen-UserService/model" - "github.com/KaySar12/NextZen-UserService/model/system_model" - "github.com/KaySar12/NextZen-UserService/pkg/config" - "github.com/KaySar12/NextZen-UserService/pkg/utils/encryption" - "github.com/KaySar12/NextZen-UserService/pkg/utils/file" - model2 "github.com/KaySar12/NextZen-UserService/service/model" + "github.com/IceWhaleTech/CasaOS-Common/external" + "github.com/IceWhaleTech/CasaOS-Common/utils/common_err" + "github.com/IceWhaleTech/CasaOS-Common/utils/jwt" + "github.com/IceWhaleTech/CasaOS-Common/utils/logger" + "github.com/IceWhaleTech/CasaOS-UserService/common" + "github.com/IceWhaleTech/CasaOS-UserService/model" + "github.com/IceWhaleTech/CasaOS-UserService/model/system_model" + "github.com/IceWhaleTech/CasaOS-UserService/pkg/config" + "github.com/IceWhaleTech/CasaOS-UserService/pkg/utils/encryption" + "github.com/IceWhaleTech/CasaOS-UserService/pkg/utils/file" + model2 "github.com/IceWhaleTech/CasaOS-UserService/service/model" uuid "github.com/satori/go.uuid" "github.com/tidwall/gjson" "go.uber.org/zap" + "golang.org/x/time/rate" - "github.com/KaySar12/NextZen-UserService/service" + "github.com/IceWhaleTech/CasaOS-UserService/service" "github.com/gin-gonic/gin" ) @@ -81,6 +86,8 @@ func PostUserRegister(c *gin.Context) { c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) } +var limiter = rate.NewLimiter(rate.Every(time.Minute), 5) + // @Summary login // @Produce application/json // @Accept application/json @@ -90,6 +97,16 @@ func PostUserRegister(c *gin.Context) { // @Success 200 {string} string "ok" // @Router /user/login [post] func PostUserLogin(c *gin.Context) { + + if !limiter.Allow() { + c.JSON(common_err.TOO_MANY_REQUEST, + model.Result{ + Success: common_err.TOO_MANY_LOGIN_REQUESTS, + Message: common_err.GetMsg(common_err.TOO_MANY_LOGIN_REQUESTS), + }) + return + } + json := make(map[string]string) c.ShouldBind(&json) @@ -108,15 +125,18 @@ func PostUserLogin(c *gin.Context) { user := service.MyService.User().GetUserAllInfoByName(username) if user.Id == 0 { c.JSON(common_err.CLIENT_ERROR, - model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)}) + model.Result{Success: common_err.USER_NOT_EXIST_OR_PWD_INVALID, Message: common_err.GetMsg(common_err.USER_NOT_EXIST_OR_PWD_INVALID)}) return } if user.Password != encryption.GetMD5ByStr(password) { c.JSON(common_err.CLIENT_ERROR, - model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)}) + model.Result{Success: common_err.USER_NOT_EXIST_OR_PWD_INVALID, Message: common_err.GetMsg(common_err.USER_NOT_EXIST_OR_PWD_INVALID)}) return } + // clean limit + limiter = rate.NewLimiter(rate.Every(time.Minute), 5) + privateKey, _ := service.MyService.User().GetKeyPair() token := system_model.VerifyInformation{} @@ -255,7 +275,7 @@ func PutUserInfo(c *gin.Context) { user := service.MyService.User().GetUserInfoById(id) if user.Id == 0 { c.JSON(common_err.SERVICE_ERROR, - model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)}) + model.Result{Success: common_err.USER_NOT_EXIST_OR_PWD_INVALID, Message: common_err.GetMsg(common_err.USER_NOT_EXIST_OR_PWD_INVALID)}) return } if len(json.Username) > 0 { @@ -507,6 +527,20 @@ func PostUserCustomConf(c *gin.Context) { return } + if name == "system" { + dataMap := make(map[string]string, 1) + dataMap["system"] = string(data) + response, err := service.MyService.MessageBus().PublishEventWithResponse(context.Background(), common.SERVICENAME, "zimaos:user:save_config", dataMap) + if err != nil { + logger.Error("failed to publish event to message bus", zap.Error(err), zap.Any("event", string(data))) + return + } + if response.StatusCode() != http.StatusOK { + logger.Error("failed to publish event to message bus", zap.String("status", response.Status()), zap.Any("response", response)) + } + + } + c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: json2.RawMessage(string(data))}) } @@ -658,23 +692,35 @@ func GetUserImage(c *gin.Context) { c.JSON(http.StatusNotFound, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) return } - if !file.Exists(filePath) { + absFilePath, err := filepath.Abs(filepath.Clean(filePath)) + if err != nil { + c.JSON(http.StatusNotFound, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) + return + } + if !file.Exists(absFilePath) { c.JSON(http.StatusNotFound, model.Result{Success: common_err.FILE_DOES_NOT_EXIST, Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST)}) return } - if !strings.Contains(filePath, config.AppInfo.UserDataPath) { + if !strings.Contains(absFilePath, config.AppInfo.UserDataPath) { c.JSON(http.StatusNotFound, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)}) return } - fileTmp, _ := os.Open(filePath) - defer fileTmp.Close() + matched, err := regexp.MatchString(`^/var/lib/casaos/\d`, absFilePath) + if err != nil { + c.JSON(http.StatusNotFound, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)}) + return + } + if !matched { + c.JSON(http.StatusNotFound, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)}) + return + } - fileName := path.Base(filePath) + fileName := path.Base(absFilePath) // @tiger - RESTful 规范下不应该返回文件本身内容,而是返回文件的静态URL,由前端去解析 c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName)) - c.File(filePath) + c.File(absFilePath) } func DeleteUserImage(c *gin.Context) { @@ -776,6 +822,11 @@ func GetUserStatus(c *gin.Context) { data["key"] = key data["initialized"] = false } + gpus, err := external.NvidiaGPUInfoList() + if err != nil { + logger.Error("NvidiaGPUInfoList error", zap.Error(err)) + } + data["gpus"] = len(gpus) c.JSON(common_err.SUCCESS, model.Result{ Success: common_err.SUCCESS, diff --git a/route/v2.go b/route/v2.go index 3b723e2..93c2c7a 100644 --- a/route/v2.go +++ b/route/v2.go @@ -7,10 +7,10 @@ import ( "strconv" "strings" - "github.com/KaySar12/NextZen-Common/utils/jwt" - codegen "github.com/KaySar12/NextZen-UserService/codegen/user_service" - v2 "github.com/KaySar12/NextZen-UserService/route/v2" - "github.com/KaySar12/NextZen-UserService/service" + "github.com/IceWhaleTech/CasaOS-Common/utils/jwt" + codegen "github.com/IceWhaleTech/CasaOS-UserService/codegen/user_service" + v2 "github.com/IceWhaleTech/CasaOS-UserService/route/v2" + "github.com/IceWhaleTech/CasaOS-UserService/service" "github.com/deepmap/oapi-codegen/pkg/middleware" "github.com/getkin/kin-openapi/openapi3" "github.com/getkin/kin-openapi/openapi3filter" diff --git a/route/v2/api_route_event.go b/route/v2/api_route_event.go index 9ad263d..180df2e 100644 --- a/route/v2/api_route_event.go +++ b/route/v2/api_route_event.go @@ -3,8 +3,8 @@ package v2 import ( "net/http" - codegen "github.com/KaySar12/NextZen-UserService/codegen/user_service" - "github.com/KaySar12/NextZen-UserService/service" + codegen "github.com/IceWhaleTech/CasaOS-UserService/codegen/user_service" + "github.com/IceWhaleTech/CasaOS-UserService/service" "github.com/labstack/echo/v4" ) diff --git a/route/v2/route.go b/route/v2/route.go index aeb5c05..eda56fb 100644 --- a/route/v2/route.go +++ b/route/v2/route.go @@ -1,6 +1,6 @@ package v2 -import codegen "github.com/KaySar12/NextZen-UserService/codegen/user_service" +import codegen "github.com/IceWhaleTech/CasaOS-UserService/codegen/user_service" type UserService struct{} diff --git a/service/event.go b/service/event.go index e1297f2..8b45ba7 100644 --- a/service/event.go +++ b/service/event.go @@ -3,7 +3,7 @@ package service import ( "encoding/json" - "github.com/KaySar12/NextZen-UserService/model" + "github.com/IceWhaleTech/CasaOS-UserService/model" "gorm.io/gorm" ) diff --git a/service/service.go b/service/service.go index c1c488e..8235635 100644 --- a/service/service.go +++ b/service/service.go @@ -1,7 +1,9 @@ package service import ( - "github.com/KaySar12/NextZen-Common/external" + "github.com/IceWhaleTech/CasaOS-Common/external" + "github.com/IceWhaleTech/CasaOS-UserService/codegen/message_bus" + "github.com/IceWhaleTech/CasaOS-UserService/pkg/config" "gorm.io/gorm" ) @@ -10,6 +12,7 @@ var MyService Repository type Repository interface { Gateway() external.ManagementService User() UserService + MessageBus() *message_bus.ClientWithResponses Event() EventService } @@ -43,3 +46,22 @@ func (c *store) Gateway() external.ManagementService { func (c *store) User() UserService { return c.user } +func (c *store) MessageBus() *message_bus.ClientWithResponses { + client, _ := message_bus.NewClientWithResponses("", func(c *message_bus.Client) error { + // error will never be returned, as we always want to return a client, even with wrong address, + // in order to avoid panic. + // + // If we don't avoid panic, message bus becomes a hard dependency, which is not what we want. + + messageBusAddress, err := external.GetMessageBusAddress(config.CommonInfo.RuntimePath) + if err != nil { + c.Server = "message bus address not found" + return nil + } + + c.Server = messageBusAddress + return nil + }) + + return client +} diff --git a/service/user.go b/service/user.go index 0d9f9cf..54bed10 100644 --- a/service/user.go +++ b/service/user.go @@ -15,9 +15,9 @@ import ( "mime/multipart" "os" - "github.com/KaySar12/NextZen-Common/utils/jwt" - "github.com/KaySar12/NextZen-Common/utils/logger" - "github.com/KaySar12/NextZen-UserService/service/model" + "github.com/IceWhaleTech/CasaOS-Common/utils/jwt" + "github.com/IceWhaleTech/CasaOS-Common/utils/logger" + "github.com/IceWhaleTech/CasaOS-UserService/service/model" "go.uber.org/zap" "gorm.io/gorm" )