* Add registration route

* add route registration

* remove ui

* 0.3.6 build scaffold (#473)

* wip

* wip

* wip

* Merge Branches

* Update helper.sh

* add goreleaser

* fix migration not working for LEGACY_WITHOUT_VERSION (#479)

* wip

* wip

* add error handling to migration script

* add migration tool

* Adjusting shell script location

* update disk user authentication method

* delayed port modification

* Update system.go

Co-authored-by: Tiger Wang (王豫) <tigerwang@outlook.com>
This commit is contained in:
link 2022-09-06 14:28:49 +08:00 committed by GitHub
parent 8d088afcc5
commit 70ba4d5e3d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
89 changed files with 1598 additions and 9228 deletions

47
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,47 @@
name: goreleaser
on:
push:
tags:
- v*.*.*
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-22.04
steps:
-
name: Install dependencies for cross-compiling
run: |
sudo apt update
sudo apt-get --no-install-recommends --yes install \
libc6-dev-amd64-cross \
gcc-aarch64-linux-gnu libc6-dev-arm64-cross \
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross
-
name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
-
name: Fetch all tags
run: git fetch --force --tags
-
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.19
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
# either 'goreleaser' (default) or 'goreleaser-pro'
distribution: goreleaser
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Your GoReleaser Pro key, if you are using the 'goreleaser-pro' distribution
# GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}

4
.gitignore vendored
View file

@ -28,8 +28,6 @@ gen
/sql/ /sql/
/out/ /out/
/db/ /db/
/docs/
/web/
/conf/conf.ini /conf/conf.ini
/conf/conf.conf /conf/conf.conf
/conf/conf.json /conf/conf.json
@ -38,6 +36,4 @@ main
CasaOS CasaOS
github.com github.com
.all-contributorsrc .all-contributorsrc
build
dist dist
.goreleaser.yaml

167
.goreleaser.yaml Normal file
View file

@ -0,0 +1,167 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
project_name: casaos
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
builds:
- id: casaos-amd64
binary: build/sysroot/usr/bin/casaos
env:
- CGO_ENABLED=1
- CC=x86_64-linux-gnu-gcc
ldflags:
- -s
- -w
- -extldflags "-static"
tags:
- musl
- netgo
goos:
- linux
goarch:
- amd64
hooks:
post:
- find build/sysroot -type f | xargs -L 1 realpath --relative-to=build/sysroot > build/sysroot.manifest
- id: casaos-arm64
binary: build/sysroot/usr/bin/casaos
env:
- CGO_ENABLED=1
- CC=aarch64-linux-gnu-gcc
ldflags:
- -s
- -w
- -extldflags "-static"
tags:
- musl
- netgo
goos:
- linux
goarch:
- arm64
hooks:
post:
- find build/sysroot -type f | xargs -L 1 realpath --relative-to=build/sysroot > build/sysroot.manifest
- id: casaos-arm-7
binary: build/sysroot/usr/bin/casaos
env:
- CGO_ENABLED=1
- CC=arm-linux-gnueabihf-gcc
ldflags:
- -s
- -w
- -extldflags "-static"
tags:
- musl
- netgo
goos:
- linux
goarch:
- arm
goarm:
- "7"
hooks:
post:
- find build/sysroot -type f | xargs -L 1 realpath --relative-to=build/sysroot > build/sysroot.manifest
- id: casaos-migration-tool-amd64
binary: build/sysroot/usr/bin/casaos-migration-tool
main: ./cmd/migration-tool
env:
- CGO_ENABLED=1
- CC=x86_64-linux-gnu-gcc
ldflags:
- -s
- -w
- -extldflags "-static"
tags:
- musl
- netgo
goos:
- linux
goarch:
- amd64
- id: casaos-migration-tool-arm64
binary: build/sysroot/usr/bin/casaos-migration-tool
main: ./cmd/migration-tool
env:
- CGO_ENABLED=1
- CC=aarch64-linux-gnu-gcc
ldflags:
- -s
- -w
- -extldflags "-static"
tags:
- musl
- netgo
goos:
- linux
goarch:
- arm64
- id: casaos-migration-tool-arm-7
binary: build/sysroot/usr/bin/casaos-migration-tool
main: ./cmd/migration-tool
env:
- CGO_ENABLED=1
- CC=arm-linux-gnueabihf-gcc
ldflags:
- -s
- -w
- -extldflags "-static"
tags:
- musl
- netgo
goos:
- linux
goarch:
- arm
goarm:
- "7"
archives:
- name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-v{{ .Version }}"
id: casaos
builds:
- casaos-amd64
- casaos-arm64
- casaos-arm-7
replacements:
arm: arm-7
files:
- build/**/*
- name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-migration-tool-v{{ .Version }}"
id: casaos-migration-tool
builds:
- casaos-migration-tool-amd64
- casaos-migration-tool-arm64
- casaos-migration-tool-arm-7
replacements:
arm: arm-7
files:
- build/sysroot/etc/**/*
checksum:
name_template: "checksums.txt"
snapshot:
name_template: "{{ incpatch .Version }}"
changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
# release:
# github:
# owner: IceWhaleTech
# name: CasaOS
# draft: true
# prerelease: auto
# mode: replace
# name_template: "v{{ .Version }}"
release:
github:
owner: LinkLeong
name: casaos-alpha
draft: true
prerelease: auto
mode: replace
name_template: "v{{ .Version }}"

View file

@ -18,7 +18,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
## [0.3.5-alpha] - 2022-08-08
## [0.3.6-alpha.1] - 2022-09-06
### Added
- [System] Added display of power and temperature to performance widget (Intel)
- [Apps] Added support for adding custom links in the APP module
### Fixed
- [Apps] Fixed the problem of not being able to modify the application pairing ([#510](https://github.com/IceWhaleTech/CasaOS/issues/510))
### Changed
- [System] Architecture optimization. Improved performance.
## [0.3.5] - 2022-08-23
### Added ### Added

1
UI

@ -1 +0,0 @@
Subproject commit bca27426e1f398c31fb6c5c23885482326514f6e

View file

@ -0,0 +1,180 @@
#!/bin/bash
set -e
# functions
__info() {
echo -e "🟩 ${1}"
}
__info_done() {
echo -e "${1}"
}
__warning() {
echo -e "🟨 ${1}"
}
__error() {
echo "🟥 ${1}"
exit 1
}
__is_version_gt() {
test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"
}
__normalize_version() {
local version
if [ "${1::1}" = "v" ]; then
version="${1:1}"
else
version="${1}"
fi
echo "$version"
}
__is_migration_needed() {
local version1
local version2
version1=$(__normalize_version "${1}")
version2=$(__normalize_version "${2}")
if [ "${version1}" = "${version2}" ]; then
return 1
fi
if [ "CURRENT_VERSION_NOT_FOUND" = "${version1}" ]; then
return 1
fi
if [ "LEGACY_WITHOUT_VERSION" = "${version1}" ]; then
return 0
fi
__is_version_gt "${version2}" "${version1}"
}
BUILD_PATH=$(dirname "${BASH_SOURCE[0]}")/../../..
SOURCE_ROOT=${BUILD_PATH}/sysroot
APP_NAME="casaos"
# APP_NAME_FORMAL="CasaOS"
APP_NAME_FORMAL="casaos-alpha"
# check if migration is needed
SOURCE_BIN_PATH=${SOURCE_ROOT}/usr/bin
SOURCE_BIN_FILE=${SOURCE_BIN_PATH}/${APP_NAME}
CURRENT_BIN_PATH=/usr/bin
CURRENT_BIN_PATH_LEGACY=/usr/local/bin
CURRENT_BIN_FILE=${CURRENT_BIN_PATH}/${APP_NAME}
CURRENT_BIN_FILE_LEGACY=$(realpath -e ${CURRENT_BIN_PATH_LEGACY}/${APP_NAME} || which ${APP_NAME} || echo CURRENT_BIN_FILE_LEGACY_NOT_FOUND)
SOURCE_VERSION="$(${SOURCE_BIN_FILE} -v)"
CURRENT_VERSION="$(${CURRENT_BIN_FILE} -v || ${CURRENT_BIN_FILE_LEGACY} -v || (stat "${CURRENT_BIN_FILE_LEGACY}" > /dev/null && echo LEGACY_WITHOUT_VERSION) || echo CURRENT_VERSION_NOT_FOUND)"
__info_done "CURRENT_VERSION: ${CURRENT_VERSION}"
__info_done "SOURCE_VERSION: ${SOURCE_VERSION}"
NEED_MIGRATION=$(__is_migration_needed "${CURRENT_VERSION}" "${SOURCE_VERSION}" && echo "true" || echo "false")
if [ "${NEED_MIGRATION}" = "false" ]; then
__info_done "Migration is not needed."
exit 0
fi
MIGRATION_SERVICE_DIR=${1}
if [ -z "${MIGRATION_SERVICE_DIR}" ]; then
MIGRATION_SERVICE_DIR=${BUILD_PATH}/scripts/migration/service.d/${APP_NAME}
fi
MIGRATION_LIST_FILE=${MIGRATION_SERVICE_DIR}/migration.list
MIGRATION_PATH=()
CURRENT_VERSION_FOUND="false"
# a VERSION_PAIR looks like "v0.3.5 v0.3.6-alpha2"
#
# - "v0.3.5" is the current version installed on this host
# - "v0.3.6-alpha2" is the version of the migration tool from GitHub
while read -r VERSION_PAIR; do
if [ -z "${VERSION_PAIR}" ]; then
continue
fi
# obtain "v0.3.5" from "v0.3.5 v0.3.6-alpha2"
VER1=$(echo "${VERSION_PAIR}" | cut -d' ' -f1)
# obtain "v0.3.6-alpha2" from "v0.3.5 v0.3.6-alpha2"
VER2=$(echo "${VERSION_PAIR}" | cut -d' ' -f2)
if [ "${CURRENT_VERSION}" = "${VER1// /}" ] || [ "${CURRENT_VERSION}" = "LEGACY_WITHOUT_VERSION" ]; then
CURRENT_VERSION_FOUND="true"
fi
if [ "${CURRENT_VERSION_FOUND}" = "true" ]; then
MIGRATION_PATH+=("${VER2// /}")
fi
done < "${MIGRATION_LIST_FILE}"
if [ ${#MIGRATION_PATH[@]} -eq 0 ]; then
__warning "No migration path found from ${CURRENT_VERSION} to ${SOURCE_VERSION}"
exit 0
fi
ARCH="unknown"
case $(uname -m) in
x86_64)
ARCH="amd64"
;;
aarch64)
ARCH="arm64"
;;
armv7l)
ARCH="arm-7"
;;
*)
__error "Unsupported architecture"
;;
esac
pushd "${MIGRATION_SERVICE_DIR}"
{ for VER2 in "${MIGRATION_PATH[@]}"; do
MIGRATION_TOOL_FILE=linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz
if [ -f "${MIGRATION_TOOL_FILE}" ]; then
__info "Migration tool ${MIGRATION_TOOL_FILE} exists. Skip downloading."
continue
fi
MIGRATION_TOOL_URL=https://github.com/LinkLeong/"${APP_NAME_FORMAL}"/releases/download/"${VER2}"/linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz
echo "Dowloading ${MIGRATION_TOOL_URL}..."
curl -sL -O "${MIGRATION_TOOL_URL}"
done
} || {
popd
__error "Failed to download migration tools"
}
{
for VER2 in "${MIGRATION_PATH[@]}"; do
MIGRATION_TOOL_FILE=linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz
__info "Extracting ${MIGRATION_TOOL_FILE}..."
tar zxvf "${MIGRATION_TOOL_FILE}" || __error "Failed to extract ${MIGRATION_TOOL_FILE}"
MIGRATION_TOOL_PATH=build/sysroot/usr/bin/${APP_NAME}-migration-tool
__info "Running ${MIGRATION_TOOL_PATH}..."
${MIGRATION_TOOL_PATH}
done
} || {
popd
__error "Failed to extract and run migration tools"
}
popd

View file

@ -0,0 +1,3 @@
LEGACY_WITHOUT_VERSION v0.3.6
v0.3.5 v0.3.6
v0.3.5.1 v0.3.6

View file

@ -0,0 +1,54 @@
#!/bin/bash
set -e
BUILD_PATH=$(dirname "${BASH_SOURCE[0]}")/../../..
APP_NAME_SHORT=casaos
__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
} || {
pushd "${ID_LIKE}" >/dev/null
} || {
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)
SETUP_SCRIPT_FILENAME="setup-${APP_NAME_SHORT}.sh"
SETUP_SCRIPT_FILEPATH="${SETUP_SCRIPT_DIRECTORY}/${SETUP_SCRIPT_FILENAME}"
{
echo "🟩 Running ${SETUP_SCRIPT_FILENAME}..."
$SHELL "${SETUP_SCRIPT_FILEPATH}" "${BUILD_PATH}"
} || {
echo "🟥 ${SETUP_SCRIPT_FILENAME} failed."
exit 1
}
echo "${SETUP_SCRIPT_FILENAME} finished."

View file

@ -0,0 +1 @@
../setup-casaos.sh

View file

@ -0,0 +1,45 @@
#!/bin/bash
###
# @Author: LinkLeong link@icewhale.org
# @Date: 2022-08-25 11:41:22
# @LastEditors: LinkLeong
# @LastEditTime: 2022-08-31 17:54:17
# @FilePath: /CasaOS/build/scripts/setup/service.d/casaos/debian/setup-casaos.sh
# @Description:
# @Website: https://www.casaos.io
# Copyright (c) 2022 by icewhale, All Rights Reserved.
###
set -e
APP_NAME="casaos"
# copy config files
CONF_PATH=/etc/casaos
OLD_CONF_PATH=/etc/casaos.conf
CONF_FILE=${CONF_PATH}/${APP_NAME}.conf
CONF_FILE_SAMPLE=${CONF_PATH}/${APP_NAME}.conf.sample
if [ -f "${OLD_CONF_PATH}" ]; then
echo "copy old conf"
cp "${OLD_CONF_PATH}" "${CONF_FILE}"
fi
if [ ! -f "${CONF_FILE}" ]; then
echo "Initializing config file..."
cp -v "${CONF_FILE_SAMPLE}" "${CONF_FILE}"
fi
if systemctl is-active "${APP_NAME}.service" &>/dev/null ;then
echo "server started"
else
# enable and start service
systemctl daemon-reload
echo "Enabling service..."
systemctl enable --force --no-ask-password "${APP_NAME}.service"
echo "Starting service..."
systemctl start --force --no-ask-password "${APP_NAME}.service"
fi

View file

@ -0,0 +1 @@
../setup-casaos.sh

View file

@ -0,0 +1 @@
../debian/setup-casaos.sh

View file

@ -0,0 +1,23 @@
[app]
PAGE_SIZE = 10
RuntimeRootPath = runtime/
LogPath = /var/log/casaos/
LogSaveName = log
LogFileExt = log
DateStrFormat = 20060102
DateTimeFormat = 2006-01-02 15:04:05
TimeFormat = 15:04:05
DateFormat = 2006-01-02
DBPath = /var/lib/casaos
ShellPath = /usr/share/casaos/shell
UserDataPath = /var/lib/casaos/conf
TempPath = /var/lib/casaos/temp
[server]
RunMode = release
ServerApi = https://api.casaos.io/casaos-api
Handshake = socket.casaos.io
Token =
USBAutoMount =
[system]

View file

@ -0,0 +1,12 @@
[Unit]
After=casaos-gateway.service
ConditionFileNotEmpty=/etc/casaos/casaos.conf
Description=CasaOS Service
[Service]
ExecStart=/usr/bin/casaos -c /etc/casaos/casaos.conf
PIDFile=/var/run/casaos/casaos.pid
Restart=always
[Install]
WantedBy=multi-user.target

47
cmd/migration-tool/log.go Normal file
View file

@ -0,0 +1,47 @@
/*
* @Author: LinkLeong link@icewhale.org
* @Date: 2022-08-30 22:15:30
* @LastEditors: LinkLeong
* @LastEditTime: 2022-08-30 22:15:47
* @FilePath: /CasaOS/cmd/migration-tool/log.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package main
import (
"log"
"os"
)
type Logger struct {
DebugMode bool
_debug *log.Logger
_info *log.Logger
_error *log.Logger
}
func NewLogger() *Logger {
return &Logger{
DebugMode: false,
_debug: log.New(os.Stdout, "DEBUG: ", 0),
_info: log.New(os.Stdout, "", 0),
_error: log.New(os.Stderr, "ERROR: ", 0),
}
}
func (l *Logger) Debug(format string, v ...interface{}) {
if l.DebugMode {
l._debug.Printf(format, v...)
}
}
func (l *Logger) Info(format string, v ...interface{}) {
l._info.Printf(format, v...)
}
func (l *Logger) Error(format string, v ...interface{}) {
l._error.Printf(format, v...)
}

117
cmd/migration-tool/main.go Normal file
View file

@ -0,0 +1,117 @@
/*
* @Author: LinkLeong link@icewhale.org
* @Date: 2022-08-23 18:09:11
* @LastEditors: LinkLeong
* @LastEditTime: 2022-08-31 14:17:51
* @FilePath: /CasaOS/cmd/migration-tool/main.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package main
import (
"flag"
"fmt"
"os"
interfaces "github.com/IceWhaleTech/CasaOS-Common"
"github.com/IceWhaleTech/CasaOS-Common/utils/systemctl"
"github.com/IceWhaleTech/CasaOS-Gateway/common"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/sqlite"
"github.com/IceWhaleTech/CasaOS/service"
"gorm.io/gorm"
)
const (
casaosServiceName = "casaos.service"
)
var _logger *Logger
var sqliteDB *gorm.DB
var configFlag = ""
var dbFlag = ""
func init() {
config.InitSetup(configFlag)
config.UpdateSetup()
if len(dbFlag) == 0 {
dbFlag = config.AppInfo.DBPath + "/db"
}
sqliteDB = sqlite.GetDb(dbFlag)
//gredis.GetRedisConn(config.RedisInfo),
service.MyService = service.NewService(sqliteDB, "")
}
func main() {
versionFlag := flag.Bool("v", false, "version")
debugFlag := flag.Bool("d", true, "debug")
forceFlag := flag.Bool("f", true, "force")
flag.Parse()
_logger = NewLogger()
if *versionFlag {
fmt.Println(common.Version)
os.Exit(0)
}
if os.Getuid() != 0 {
os.Exit(1)
}
if *debugFlag {
_logger.DebugMode = true
}
if !*forceFlag {
serviceEnabled, err := systemctl.IsServiceEnabled(casaosServiceName)
if err != nil {
panic(err)
}
if serviceEnabled {
_logger.Info("%s is already enabled. If migration is still needed, try with -f.", casaosServiceName)
os.Exit(1)
}
}
migrationTools := []interfaces.MigrationTool{
NewMigrationToolFor_035(),
}
var selectedMigrationTool interfaces.MigrationTool
// look for the right migration tool matching current version
for _, tool := range migrationTools {
migrationNeeded, err := tool.IsMigrationNeeded()
if err != nil {
panic(err)
}
if migrationNeeded {
selectedMigrationTool = tool
break
}
}
if selectedMigrationTool == nil {
_logger.Error("selectedMigrationTool is null")
return
}
if err := selectedMigrationTool.PreMigrate(); err != nil {
panic(err)
}
if err := selectedMigrationTool.Migrate(); err != nil {
panic(err)
}
selectedMigrationTool.PostMigrate()
_logger.Info("casaos migration ok")
//panic(err)
}

View file

@ -0,0 +1,182 @@
/*
* @Author: LinkLeong link@icewhale.org
* @Date: 2022-08-24 17:36:00
* @LastEditors: LinkLeong
* @LastEditTime: 2022-09-05 11:24:27
* @FilePath: /CasaOS/cmd/migration-tool/migration-034-035.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package main
import (
"io"
"io/ioutil"
"os"
"path"
"strings"
interfaces "github.com/IceWhaleTech/CasaOS-Common"
"github.com/IceWhaleTech/CasaOS-Common/utils/version"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/service"
)
type migrationTool struct{}
func (u *migrationTool) IsMigrationNeeded() (bool, error) {
majorVersion, minorVersion, patchVersion, err := version.DetectLegacyVersion()
if err != nil {
if err == version.ErrLegacyVersionNotFound {
return false, nil
}
return false, err
}
if majorVersion > 0 {
return false, nil
}
if minorVersion > 3 {
return false, nil
}
if minorVersion == 3 && patchVersion > 5 {
return false, nil
}
_logger.Info("Migration is needed for a CasaOS version 0.3.5 and older...")
return true, nil
}
func (u *migrationTool) PreMigrate() error {
return nil
}
func (u *migrationTool) Migrate() error {
if service.MyService.System().GetSysInfo().KernelArch == "aarch64" && config.ServerInfo.USBAutoMount != "True" && strings.Contains(service.MyService.System().GetDeviceTree(), "Raspberry Pi") {
service.MyService.System().UpdateUSBAutoMount("False")
service.MyService.System().ExecUSBAutoMountShell("False")
}
newAPIUrl := "https://api.casaos.io/casaos-api"
if config.ServerInfo.ServerApi == "https://api.casaos.zimaboard.com" {
config.ServerInfo.ServerApi = newAPIUrl
config.Cfg.Section("server").Key("ServerApi").SetValue(newAPIUrl)
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
command.OnlyExec("curl -fsSL https://raw.githubusercontent.com/IceWhaleTech/get/main/assist.sh | bash")
if !file.CheckNotExist("/casaOS") {
command.OnlyExec("source /casaOS/server/shell/update.sh ;")
command.OnlyExec("source " + config.AppInfo.ShellPath + "/delete-old-service.sh ;")
}
service.MyService.App().ImportApplications(true)
src := "/casaOS/server/conf/conf.ini"
if file.Exists(src) {
dst := "/etc/casaos/casaos.conf"
source, err := os.Open(src)
if err != nil {
return err
}
defer source.Close()
destination, err := os.Create(dst)
if err != nil {
return err
}
defer destination.Close()
_, err = io.Copy(destination, source)
if err != nil {
return err
}
}
if file.Exists("/casaOS/server/db") {
var fds []os.FileInfo
var err error
to := "/var/lib/casaos/db"
file.IsNotExistMkDir(to)
from := "/casaOS/server/db"
if fds, err = ioutil.ReadDir(from); err != nil {
return err
}
for _, fd := range fds {
srcfp := path.Join(from, fd.Name())
dstfp := path.Join(to, fd.Name())
source, err := os.Open(srcfp)
if err != nil {
return err
}
defer source.Close()
destination, err := os.Create(dstfp)
if err != nil {
return err
}
defer destination.Close()
_, err = io.Copy(destination, source)
if err != nil {
return err
}
}
}
if file.Exists("/casaOS/server/conf") {
var fds []os.FileInfo
var err error
to := "/var/lib/casaos/conf"
file.IsNotExistMkDir(to)
from := "/casaOS/server/conf"
if fds, err = ioutil.ReadDir(from); err != nil {
return err
}
for _, fd := range fds {
fExt := path.Ext(fd.Name())
if fExt != ".json" {
continue
}
srcfp := path.Join(from, fd.Name())
dstfp := path.Join(to, fd.Name())
source, err := os.Open(srcfp)
if err != nil {
return err
}
defer source.Close()
destination, err := os.Create(dstfp)
if err != nil {
return err
}
defer destination.Close()
_, err = io.Copy(destination, source)
if err != nil {
return err
}
}
}
_logger.Info("update done")
return nil
}
func (u *migrationTool) PostMigrate() error {
return nil
}
func NewMigrationToolFor_035() interfaces.MigrationTool {
return &migrationTool{}
}

View file

@ -14,7 +14,6 @@ UserDataPath = /var/lib/casaos/conf
TempPath = /var/lib/casaos/temp TempPath = /var/lib/casaos/temp
[server] [server]
HttpPort = 80
RunMode = release RunMode = release
ServerApi = https://api.casaos.io/casaos-api ServerApi = https://api.casaos.io/casaos-api
Handshake = socket.casaos.io Handshake = socket.casaos.io
@ -22,3 +21,6 @@ Token =
USBAutoMount = USBAutoMount =
[system] [system]
[common]
RuntimePath=/var/run/casaos

40
go.mod
View file

@ -4,52 +4,38 @@ go 1.16
require ( require (
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d
github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220901034123-ca130f6b5ce9
github.com/IceWhaleTech/CasaOS-Gateway v0.3.6
github.com/Microsoft/go-winio v0.5.0 // indirect github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/Microsoft/hcsshim v0.8.22 // indirect
github.com/ambelovsky/go-structs v1.1.0 // indirect github.com/ambelovsky/go-structs v1.1.0 // indirect
github.com/ambelovsky/gosf v0.0.0-20201109201340-237aea4d6109 github.com/ambelovsky/gosf v0.0.0-20201109201340-237aea4d6109
github.com/ambelovsky/gosf-socketio v0.0.0-20201109193639-add9d32f8b19 // indirect github.com/ambelovsky/gosf-socketio v0.0.0-20201109193639-add9d32f8b19 // indirect
github.com/bits-and-blooms/bitset v1.2.1 // indirect github.com/containerd/containerd v1.5.7 // indirect
github.com/containerd/containerd v1.5.7
github.com/containerd/continuity v0.2.0 // indirect
github.com/disintegration/imaging v1.6.2 github.com/disintegration/imaging v1.6.2
github.com/docker/distribution v2.8.0+incompatible // indirect github.com/docker/distribution v2.8.0+incompatible // indirect
github.com/docker/docker v20.10.7+incompatible github.com/docker/docker v20.10.7+incompatible
github.com/docker/go-connections v0.4.0 github.com/docker/go-connections v0.4.0
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
github.com/gin-contrib/gzip v0.0.2 github.com/gin-contrib/gzip v0.0.6
github.com/gin-gonic/gin v1.7.2 github.com/gin-gonic/gin v1.8.1
github.com/go-ini/ini v1.62.0 github.com/go-ini/ini v1.62.0
github.com/go-playground/validator/v10 v10.6.1 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/golang-jwt/jwt/v4 v4.4.1
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
github.com/gomodule/redigo v1.8.5 github.com/gomodule/redigo v1.8.5
github.com/google/go-github/v36 v36.0.0 github.com/google/go-github/v36 v36.0.0
github.com/google/uuid v1.3.0 // indirect
github.com/googollee/go-socket.io v1.6.2 github.com/googollee/go-socket.io v1.6.2
github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
github.com/hirochachacha/go-smb2 v1.1.0 github.com/hirochachacha/go-smb2 v1.1.0
github.com/jinzhu/copier v0.3.2 github.com/jinzhu/copier v0.3.2
github.com/json-iterator/go v1.1.11 // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/lucas-clemente/quic-go v0.25.0 github.com/lucas-clemente/quic-go v0.25.0
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-sqlite3 v1.14.11 // indirect
github.com/mholt/archiver/v3 v3.5.1 github.com/mholt/archiver/v3 v3.5.1
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/morikuni/aec v1.0.0 // indirect github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/selinux v1.8.5 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pilebones/go-udev v0.9.0 github.com/pilebones/go-udev v0.9.0
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/prometheus/procfs v0.7.3 // indirect
github.com/robfig/cron v1.2.0 github.com/robfig/cron v1.2.0
github.com/satori/go.uuid v1.2.0 github.com/satori/go.uuid v1.2.0
github.com/shirou/gopsutil/v3 v3.22.7 github.com/shirou/gopsutil/v3 v3.22.7
@ -58,22 +44,12 @@ require (
github.com/smartystreets/goconvey v1.6.4 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
github.com/tidwall/gjson v1.10.2 github.com/tidwall/gjson v1.10.2
github.com/ugorji/go v1.2.6 // indirect go.uber.org/zap v1.21.0
go.opencensus.io v0.23.0 // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
go.uber.org/zap v1.10.0
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
golang.org/x/mod v0.5.0 // indirect golang.org/x/mod v0.5.0 // indirect
golang.org/x/net v0.0.0-20211020060615-d418f374d309 // indirect golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
golang.org/x/tools v0.1.7 // indirect golang.org/x/tools v0.1.7 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0 // indirect
google.golang.org/grpc v1.41.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0
gorm.io/driver/sqlite v1.2.6 gorm.io/driver/sqlite v1.2.6
gorm.io/gorm v1.22.5 gorm.io/gorm v1.22.5

475
go.sum

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,18 @@
/*
* @Author: LinkLeong link@icewhale.org
* @Date: 2022-08-24 17:37:36
* @LastEditors: LinkLeong
* @LastEditTime: 2022-08-24 17:38:48
* @FilePath: /CasaOS/interfaces/migrationTool.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package interfaces
type MigrationTool interface {
IsMigrationNeeded() (bool, error)
PostMigrate() error
Migrate() error
PreMigrate() error
}

84
main.go
View file

@ -3,16 +3,16 @@ package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"net"
"net/http" "net/http"
"time" "time"
"github.com/IceWhaleTech/CasaOS-Gateway/common"
"github.com/IceWhaleTech/CasaOS/model/notify" "github.com/IceWhaleTech/CasaOS/model/notify"
"github.com/IceWhaleTech/CasaOS/pkg/cache" "github.com/IceWhaleTech/CasaOS/pkg/cache"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/sqlite" "github.com/IceWhaleTech/CasaOS/pkg/sqlite"
"github.com/IceWhaleTech/CasaOS/pkg/utils/encryption"
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger" "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/IceWhaleTech/CasaOS/pkg/utils/random"
"github.com/IceWhaleTech/CasaOS/route" "github.com/IceWhaleTech/CasaOS/route"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
"github.com/IceWhaleTech/CasaOS/types" "github.com/IceWhaleTech/CasaOS/types"
@ -21,17 +21,17 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
) )
const LOCALHOST = "127.0.0.1"
var sqliteDB *gorm.DB var sqliteDB *gorm.DB
var configFlag = flag.String("c", "", "config address") var configFlag = flag.String("c", "", "config address")
var dbFlag = flag.String("db", "", "db path") var dbFlag = flag.String("db", "", "db path")
var resetUser = flag.Bool("ru", false, "reset user") var versionFlag = flag.Bool("v", false, "version")
var user = flag.String("user", "", "user name")
var version = flag.Bool("v", false, "show version")
func init() { func init() {
flag.Parse() flag.Parse()
if *version { if *versionFlag {
fmt.Println("v" + types.CURRENTVERSION) fmt.Println("v" + types.CURRENTVERSION)
return return
} }
@ -46,7 +46,7 @@ func init() {
sqliteDB = sqlite.GetDb(*dbFlag) sqliteDB = sqlite.GetDb(*dbFlag)
//gredis.GetRedisConn(config.RedisInfo), //gredis.GetRedisConn(config.RedisInfo),
service.MyService = service.NewService(sqliteDB) service.MyService = service.NewService(sqliteDB, config.CommonInfo.RuntimePath)
service.Cache = cache.Init() service.Cache = cache.Init()
@ -73,31 +73,14 @@ func init() {
// @BasePath /v1 // @BasePath /v1
func main() { func main() {
service.NotifyMsg = make(chan notify.Message, 10) service.NotifyMsg = make(chan notify.Message, 10)
if *version { if *versionFlag {
return
}
if *resetUser {
if user == nil || len(*user) == 0 {
fmt.Println("user is empty")
return
}
userData := service.MyService.User().GetUserAllInfoByName(*user)
if userData.Id == 0 {
fmt.Println("user not exist")
return
}
password := random.RandomString(6, false)
userData.Password = encryption.GetMD5ByStr(password)
service.MyService.User().UpdateUserPassword(userData)
fmt.Println("User reset successful")
fmt.Println("UserName:" + userData.Username)
fmt.Println("Password:" + password)
return return
} }
go route.SocketInit(service.NotifyMsg) go route.SocketInit(service.NotifyMsg)
go route.MonitoryUSB() go route.MonitoryUSB()
//model.Setup() //model.Setup()
//gredis.Setup() //gredis.Setup()
r := route.InitRouter() r := route.InitRouter()
//service.SyncTask(sqliteDB) //service.SyncTask(sqliteDB)
cron2 := cron.New() cron2 := cron.New()
@ -117,18 +100,49 @@ func main() {
fmt.Println(err) fmt.Println(err)
} }
cron2.Start() cron2.Start()
defer cron2.Stop() defer cron2.Stop()
s := &http.Server{
Addr: fmt.Sprintf(":%v", config.ServerInfo.HttpPort), listener, err := net.Listen("tcp", net.JoinHostPort(LOCALHOST, "0"))
Handler: r, if err != nil {
ReadTimeout: 60 * time.Second, panic(err)
WriteTimeout: 60 * time.Second,
MaxHeaderBytes: 1 << 20,
} }
routers := []string{"sys", "apps", "container", "app-categories", "port", "file", "folder", "batch", "image", "disks", "storage", "samba"}
for _, v := range routers {
err = service.MyService.Gateway().CreateRoute(&common.Route{
Path: "/v1/" + v,
Target: "http://" + listener.Addr().String(),
})
s.ListenAndServe() if err != nil {
fmt.Println("err", err)
panic(err)
}
}
go func() {
time.Sleep(time.Second * 2)
//v0.3.6
if config.ServerInfo.HttpPort != "" {
changePort := common.ChangePortRequest{}
changePort.Port = config.ServerInfo.HttpPort
err := service.MyService.Gateway().ChangePort(&changePort)
if err == nil {
config.Cfg.Section("server").Key("HttpPort").SetValue("")
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
}
}()
// if err := r.Run(fmt.Sprintf(":%v", config.ServerInfo.HttpPort)); err != nil { // s := &http.Server{
// fmt.Println("failed run app: ", err) // Addr: listener.Addr().String(), //fmt.Sprintf(":%v", config.ServerInfo.HttpPort),
// Handler: r,
// ReadTimeout: 60 * time.Second,
// WriteTimeout: 60 * time.Second,
// MaxHeaderBytes: 1 << 20,
// } // }
// s.ListenAndServe()
err = http.Serve(listener, r)
if err != nil {
panic(err)
}
} }

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com * @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46 * @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong * @LastEditors: LinkLeong
* @LastEditTime: 2022-07-14 11:02:06 * @LastEditTime: 2022-09-02 22:12:34
* @FilePath: /CasaOS/model/sys_common.go * @FilePath: /CasaOS/model/sys_common.go
* @Description: * @Description:
* @Website: https://www.casaos.io * @Website: https://www.casaos.io
@ -17,20 +17,6 @@ type SysInfoModel struct {
Name string //系统名称 Name string //系统名称
} }
//用户相关
type UserModel struct {
UserName string
PWD string
Token string
Head string
Email string
Description string
Initialized bool
Avatar string
NickName string
Public string
}
//服务配置 //服务配置
type ServerModel struct { type ServerModel struct {
HttpPort string HttpPort string
@ -56,6 +42,9 @@ type APPModel struct {
ShellPath string ShellPath string
TempPath string TempPath string
} }
type CommonModel struct {
RuntimePath string
}
//公共返回模型 //公共返回模型
type Result struct { type Result struct {

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com * @Author: LinkLeong link@icewhale.com
* @Date: 2021-09-30 18:18:14 * @Date: 2021-09-30 18:18:14
* @LastEditors: LinkLeong * @LastEditors: LinkLeong
* @LastEditTime: 2022-06-21 11:09:30 * @LastEditTime: 2022-08-31 17:04:02
* @FilePath: /CasaOS/pkg/config/config.go * @FilePath: /CasaOS/pkg/config/config.go
* @Description: * @Description:
* @Website: https://www.casaos.io * @Website: https://www.casaos.io
@ -11,5 +11,5 @@
package config package config
const ( const (
USERCONFIGURL = "/etc/casaos.conf" USERCONFIGURL = "/etc/casaos/casaos.conf"
) )

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com * @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46 * @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong * @LastEditors: LinkLeong
* @LastEditTime: 2022-07-14 10:58:45 * @LastEditTime: 2022-09-05 11:58:02
* @FilePath: /CasaOS/pkg/config/init.go * @FilePath: /CasaOS/pkg/config/init.go
* @Description: * @Description:
* @Website: https://www.casaos.io * @Website: https://www.casaos.io
@ -26,12 +26,11 @@ import (
//系统配置 //系统配置
var SysInfo = &model.SysInfoModel{} var SysInfo = &model.SysInfoModel{}
//用户相关
var UserInfo = &model.UserModel{}
//用户相关 //用户相关
var AppInfo = &model.APPModel{} var AppInfo = &model.APPModel{}
var CommonInfo = &model.CommonModel{}
//var RedisInfo = &model.RedisModel{} //var RedisInfo = &model.RedisModel{}
//server相关 //server相关
@ -58,38 +57,42 @@ func InitSetup(config string) {
var err error var err error
//读取文件 //读取文件
Cfg, err = ini.Load(configDir) Cfg, err = ini.Load(configDir)
if err != nil {
Cfg, err = ini.Load("/etc/casaos.conf")
if err != nil {
Cfg, err = ini.Load("/casaOS/server/conf/conf.ini")
if err != nil { if err != nil {
fmt.Printf("Fail to read file: %v", err) fmt.Printf("Fail to read file: %v", err)
os.Exit(1) os.Exit(1)
} }
}
mapTo("user", UserInfo) }
mapTo("app", AppInfo) mapTo("app", AppInfo)
//mapTo("redis", RedisInfo) //mapTo("redis", RedisInfo)
mapTo("server", ServerInfo) mapTo("server", ServerInfo)
mapTo("system", SystemConfigInfo) mapTo("system", SystemConfigInfo)
mapTo("file", FileSettingInfo) mapTo("file", FileSettingInfo)
mapTo("common", CommonInfo)
SystemConfigInfo.ConfigPath = configDir SystemConfigInfo.ConfigPath = configDir
if len(AppInfo.DBPath) == 0 { if len(AppInfo.DBPath) == 0 {
AppInfo.DBPath = "/var/lib/casaos" AppInfo.DBPath = "/var/lib/casaos"
Cfg.SaveTo(configDir)
} }
if len(AppInfo.LogPath) == 0 { if len(AppInfo.LogPath) == 0 {
AppInfo.LogPath = "/var/log/casaos/" AppInfo.LogPath = "/var/log/casaos/"
Cfg.SaveTo(configDir)
} }
if len(AppInfo.ShellPath) == 0 { if len(AppInfo.ShellPath) == 0 {
AppInfo.ShellPath = "/usr/share/casaos/shell" AppInfo.ShellPath = "/usr/share/casaos/shell"
Cfg.SaveTo(configDir)
} }
if len(AppInfo.UserDataPath) == 0 { if len(AppInfo.UserDataPath) == 0 {
AppInfo.UserDataPath = "/var/lib/casaos/conf" AppInfo.UserDataPath = "/var/lib/casaos/conf"
Cfg.SaveTo(configDir)
} }
if len(AppInfo.TempPath) == 0 { if len(AppInfo.TempPath) == 0 {
AppInfo.TempPath = "/var/lib/casaos/temp" AppInfo.TempPath = "/var/lib/casaos/temp"
Cfg.SaveTo(configDir)
} }
if len(CommonInfo.RuntimePath) == 0 {
CommonInfo.RuntimePath = "/var/run/casaos"
}
Cfg.SaveTo(configDir)
// AppInfo.ProjectPath = getCurrentDirectory() //os.Getwd() // AppInfo.ProjectPath = getCurrentDirectory() //os.Getwd()
} }

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com * @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46 * @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong * @LastEditors: LinkLeong
* @LastEditTime: 2022-07-27 11:25:26 * @LastEditTime: 2022-08-31 13:39:24
* @FilePath: /CasaOS/pkg/sqlite/db.go * @FilePath: /CasaOS/pkg/sqlite/db.go
* @Description: * @Description:
* @Website: https://www.casaos.io * @Website: https://www.casaos.io
@ -43,17 +43,7 @@ func GetDb(dbPath string) *gorm.DB {
} }
gdb = db gdb = db
db.Exec(`alter table o_user rename to old_user; err = db.AutoMigrate(&model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.SharesDBModel{}, model2.ConnectionsDBModel{})
create table o_users ( id integer primary key,username text,password text,role text,email text,nickname text,avatar text,description text,created_at datetime,updated_at datetime);
insert into o_users select id,user_name,password,role,email,nick_name,avatar,description,created_at,updated_at from old_user;
drop table old_user;
drop table o_user;
`)
err = db.AutoMigrate(&model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.UserDBModel{}, model2.SharesDBModel{}, model2.ConnectionsDBModel{})
db.Exec("DROP TABLE IF EXISTS o_application") db.Exec("DROP TABLE IF EXISTS o_application")
db.Exec("DROP TABLE IF EXISTS o_friend") db.Exec("DROP TABLE IF EXISTS o_friend")
db.Exec("DROP TABLE IF EXISTS o_person_download") db.Exec("DROP TABLE IF EXISTS o_person_download")

View file

@ -1,63 +0,0 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2021-09-30 18:18:14
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-18 17:30:38
* @FilePath: /CasaOS/pkg/utils/jwt/jwt.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package jwt
import (
"time"
jwt "github.com/golang-jwt/jwt/v4"
)
type Claims struct {
Username string `json:"username"`
PassWord string `json:"password"`
Id int `json:"id"`
jwt.RegisteredClaims
}
var jwtSecret []byte
//创建token
func GenerateToken(username, password string, id int, issuer string, t time.Duration) (string, error) {
clims := Claims{
username,
password,
id,
jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(t)),
IssuedAt: jwt.NewNumericDate(time.Now()),
NotBefore: jwt.NewNumericDate(time.Now()),
Issuer: issuer,
},
}
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, clims)
token, err := tokenClaims.SignedString(jwtSecret)
return token, err
}
//解析token
func ParseToken(token string, valid bool) (*Claims, error) {
tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if tokenClaims != nil {
if clims, ok := tokenClaims.Claims.(*Claims); ok {
if valid && tokenClaims.Valid {
return clims, nil
} else if !valid {
return clims, nil
}
}
}
return nil, err
}

View file

@ -1,75 +0,0 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-06-17 14:01:25
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-29 16:22:25
* @FilePath: /CasaOS/pkg/utils/jwt/jwt_helper.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package jwt
import (
"fmt"
"strconv"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/gin-gonic/gin"
)
func JWT() gin.HandlerFunc {
return func(c *gin.Context) {
var code int
code = common_err.SUCCESS
token := c.GetHeader("Authorization")
if len(token) == 0 {
token = c.Query("token")
}
if token == "" {
code = common_err.INVALID_PARAMS
}
claims, err := ParseToken(token, false)
//_, err := ParseToken(token)
if err != nil {
code = common_err.ERROR_AUTH_TOKEN
} else if (c.Request.URL.Path == "/v1/file" || c.Request.URL.Path == "/v1/image" || c.Request.URL.Path == "/v1/file/upload" || c.Request.URL.Path == "/v1/batch") && claims.VerifyIssuer("casaos", true) {
//Special treatment
} else if !claims.VerifyExpiresAt(time.Now(), true) || !claims.VerifyIssuer("casaos", true) {
code = common_err.ERROR_AUTH_TOKEN
}
if code != common_err.SUCCESS {
c.JSON(code, model.Result{Success: code, Message: common_err.GetMsg(code)})
c.Abort()
return
}
c.Request.Header.Add("user_id", strconv.Itoa(claims.Id))
c.Next()
}
}
//get AccessToken
func GetAccessToken(username, pwd string, id int) string {
token, err := GenerateToken(username, pwd, id, "casaos", 3*time.Hour*time.Duration(1))
if err == nil {
return token
} else {
loger2.Error(fmt.Sprintf("Get Token Fail: %V", err))
return ""
}
}
func GetRefreshToken(username, pwd string, id int) string {
token, err := GenerateToken(username, pwd, id, "refresh", 7*24*time.Hour*time.Duration(1))
if err == nil {
return token
} else {
loger2.Error(fmt.Sprintf("Get Token Fail: %V", err))
return ""
}
}

View file

@ -5,7 +5,7 @@
* @Author: LinkLeong link@icewhale.org * @Author: LinkLeong link@icewhale.org
* @Date: 2022-08-12 14:22:28 * @Date: 2022-08-12 14:22:28
* @LastEditors: LinkLeong * @LastEditors: LinkLeong
* @LastEditTime: 2022-08-12 18:41:14 * @LastEditTime: 2022-09-05 16:27:55
* @FilePath: /CasaOS/route/darwin.go * @FilePath: /CasaOS/route/darwin.go
* @Description: * @Description:
* @Website: https://www.casaos.io * @Website: https://www.casaos.io

View file

@ -10,25 +10,16 @@ import (
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/samba" "github.com/IceWhaleTech/CasaOS/pkg/samba"
"github.com/IceWhaleTech/CasaOS/pkg/utils/command" "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"github.com/IceWhaleTech/CasaOS/pkg/utils/encryption"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger" "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model" model2 "github.com/IceWhaleTech/CasaOS/service/model"
uuid "github.com/satori/go.uuid"
"go.uber.org/zap" "go.uber.org/zap"
) )
func InitFunction() { func InitFunction() {
ShellInit()
CheckSerialDiskMount() CheckSerialDiskMount()
CheckToken2_11()
ImportApplications()
// Soon to be removed
ChangeAPIUrl()
MoveUserToDB()
go InitNetworkMount() go InitNetworkMount()
} }
func CheckSerialDiskMount() { func CheckSerialDiskMount() {
@ -70,79 +61,6 @@ func CheckSerialDiskMount() {
service.MyService.Disk().RemoveLSBLKCache() service.MyService.Disk().RemoveLSBLKCache()
command.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;AutoRemoveUnuseDir") command.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;AutoRemoveUnuseDir")
} }
func ShellInit() {
command.OnlyExec("curl -fsSL https://raw.githubusercontent.com/IceWhaleTech/get/main/assist.sh | bash")
if !file.CheckNotExist("/casaOS") {
command.OnlyExec("source /casaOS/server/shell/update.sh ;")
command.OnlyExec("source " + config.AppInfo.ShellPath + "/delete-old-service.sh ;")
}
}
func CheckToken2_11() {
if len(config.ServerInfo.Token) == 0 {
token := uuid.NewV4().String
config.ServerInfo.Token = token()
config.Cfg.Section("server").Key("Token").SetValue(token())
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
if len(config.UserInfo.Description) == 0 {
config.Cfg.Section("user").Key("Description").SetValue("nothing")
config.UserInfo.Description = "nothing"
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
if service.MyService.System().GetSysInfo().KernelArch == "aarch64" && config.ServerInfo.USBAutoMount != "True" && strings.Contains(service.MyService.System().GetDeviceTree(), "Raspberry Pi") {
service.MyService.System().UpdateUSBAutoMount("False")
service.MyService.System().ExecUSBAutoMountShell("False")
}
// str := []string{}
// str = append(str, "ddd")
// str = append(str, "aaa")
// ddd := strings.Join(str, "|")
// config.Cfg.Section("file").Key("ShareDir").SetValue(ddd)
// config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
func ImportApplications() {
service.MyService.App().ImportApplications(true)
}
// 0.3.1
func ChangeAPIUrl() {
newAPIUrl := "https://api.casaos.io/casaos-api"
if config.ServerInfo.ServerApi == "https://api.casaos.zimaboard.com" {
config.ServerInfo.ServerApi = newAPIUrl
config.Cfg.Section("server").Key("ServerApi").SetValue(newAPIUrl)
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
}
//0.3.3
//Transferring user data to the database
func MoveUserToDB() {
if len(config.UserInfo.UserName) > 0 && service.MyService.User().GetUserInfoByUserName(config.UserInfo.UserName).Id == 0 {
user := model2.UserDBModel{}
user.Username = config.UserInfo.UserName
user.Email = config.UserInfo.Email
user.Nickname = config.UserInfo.NickName
user.Password = encryption.GetMD5ByStr(config.UserInfo.PWD)
user.Role = "admin"
user = service.MyService.User().CreateUser(user)
if user.Id > 0 {
userPath := config.AppInfo.UserDataPath + "/" + strconv.Itoa(user.Id)
file.MkDir(userPath)
os.Rename("/casaOS/server/conf/app_order.json", userPath+"/app_order.json")
}
}
}
func InitNetworkMount() { func InitNetworkMount() {
time.Sleep(time.Second * 10) time.Sleep(time.Second * 10)

View file

@ -5,7 +5,7 @@
* @Author: LinkLeong link@icewhale.com * @Author: LinkLeong link@icewhale.com
* @Date: 2022-07-01 15:11:36 * @Date: 2022-07-01 15:11:36
* @LastEditors: LinkLeong * @LastEditors: LinkLeong
* @LastEditTime: 2022-08-15 11:50:04 * @LastEditTime: 2022-09-05 16:28:46
* @FilePath: /CasaOS/route/periodical.go * @FilePath: /CasaOS/route/periodical.go
* @Description: * @Description:
* @Website: https://www.casaos.io * @Website: https://www.casaos.io
@ -180,6 +180,8 @@ func SendAllHardwareStatusBySocket() {
cpuData := make(map[string]interface{}) cpuData := make(map[string]interface{})
cpuData["percent"] = cpu cpuData["percent"] = cpu
cpuData["num"] = num cpuData["num"] = num
cpuData["temperature"] = service.MyService.System().GetCPUTemperature()
cpuData["power"] = service.MyService.System().GetCPUPower()
list := service.MyService.Disk().LSBLK(true) list := service.MyService.Disk().LSBLK(true)

View file

@ -1,20 +1,15 @@
package route package route
import ( import (
"net/http" jwt2 "github.com/IceWhaleTech/CasaOS-Common/utils/jwt"
"github.com/IceWhaleTech/CasaOS/middleware" "github.com/IceWhaleTech/CasaOS/middleware"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
jwt2 "github.com/IceWhaleTech/CasaOS/pkg/utils/jwt"
v1 "github.com/IceWhaleTech/CasaOS/route/v1" v1 "github.com/IceWhaleTech/CasaOS/route/v1"
"github.com/IceWhaleTech/CasaOS/web"
"github.com/gin-contrib/gzip" "github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
var OnlineDemo bool = false
func InitRouter() *gin.Engine { func InitRouter() *gin.Engine {
r := gin.Default() r := gin.Default()
@ -24,22 +19,22 @@ func InitRouter() *gin.Engine {
r.Use(gzip.Gzip(gzip.DefaultCompression)) r.Use(gzip.Gzip(gzip.DefaultCompression))
gin.SetMode(config.ServerInfo.RunMode) gin.SetMode(config.ServerInfo.RunMode)
r.StaticFS("/ui", http.FS(web.Static)) // r.StaticFS("/ui", http.FS(web.Static))
r.GET("/", WebUIHome) // r.GET("/", WebUIHome)
// r.StaticFS("/assets", http.Dir("./static/assets")) // r.StaticFS("/assets", http.Dir("./static/assets"))
// r.StaticFile("/favicon.ico", "./static/favicon.ico") // r.StaticFile("/favicon.ico", "./static/favicon.ico")
//r.GET("/", func(c *gin.Context) { //r.GET("/", func(c *gin.Context) {
// c.Redirect(http.StatusMovedPermanently, "ui/") // c.Redirect(http.StatusMovedPermanently, "ui/")
//}) //})
r.POST("/v1/users/register", v1.PostUserRegister) // r.POST("/v1/users/register", v1.PostUserRegister)
r.POST("/v1/users/login", v1.PostUserLogin) // r.POST("/v1/users/login", v1.PostUserLogin)
r.GET("/v1/users/name", v1.GetUserAllUsername) //all/name // r.GET("/v1/users/name", v1.GetUserAllUsername) //all/name
r.POST("/v1/users/refresh", v1.PostUserRefreshToken) // r.POST("/v1/users/refresh", v1.PostUserRefreshToken)
// No short-term modifications // // No short-term modifications
r.GET("/v1/users/image", v1.GetUserImage) // r.GET("/v1/users/image", v1.GetUserImage)
r.GET("/v1/users/status", v1.GetUserStatus) //init/check // r.GET("/v1/users/status", v1.GetUserStatus) //init/check
//r.GET("/v1/guide/check", v1.GetGuideCheck) // /v1/sys/guide_check //r.GET("/v1/guide/check", v1.GetGuideCheck) // /v1/sys/guide_check
r.GET("/v1/sys/debug", v1.GetSystemConfigDebug) // //debug r.GET("/v1/sys/debug", v1.GetSystemConfigDebug) // //debug
@ -50,28 +45,28 @@ func InitRouter() *gin.Engine {
v1Group.Use(jwt2.JWT()) v1Group.Use(jwt2.JWT())
{ {
v1UsersGroup := v1Group.Group("/users") // v1UsersGroup := v1Group.Group("/users")
v1UsersGroup.Use() // v1UsersGroup.Use()
{ // {
v1UsersGroup.GET("/current", v1.GetUserInfo) // v1UsersGroup.GET("/current", v1.GetUserInfo)
v1UsersGroup.PUT("/current", v1.PutUserInfo) // v1UsersGroup.PUT("/current", v1.PutUserInfo)
v1UsersGroup.PUT("/current/password", v1.PutUserPassword) // v1UsersGroup.PUT("/current/password", v1.PutUserPassword)
v1UsersGroup.GET("/current/custom/:key", v1.GetUserCustomConf) // v1UsersGroup.GET("/current/custom/:key", v1.GetUserCustomConf)
v1UsersGroup.POST("/current/custom/:key", v1.PostUserCustomConf) // v1UsersGroup.POST("/current/custom/:key", v1.PostUserCustomConf)
v1UsersGroup.DELETE("/current/custom/:key", v1.DeleteUserCustomConf) // v1UsersGroup.DELETE("/current/custom/:key", v1.DeleteUserCustomConf)
v1UsersGroup.POST("/current/image/:key", v1.PostUserUploadImage) // v1UsersGroup.POST("/current/image/:key", v1.PostUserUploadImage)
v1UsersGroup.PUT("/current/image/:key", v1.PutUserImage) // v1UsersGroup.PUT("/current/image/:key", v1.PutUserImage)
//v1UserGroup.POST("/file/image/:key", v1.PostUserFileImage) // //v1UserGroup.POST("/file/image/:key", v1.PostUserFileImage)
v1UsersGroup.DELETE("/current/image", v1.DeleteUserImage) // v1UsersGroup.DELETE("/current/image", v1.DeleteUserImage)
//v1UserGroup.PUT("/avatar", v1.PutUserAvatar) // //v1UserGroup.PUT("/avatar", v1.PutUserAvatar)
//v1UserGroup.GET("/avatar", v1.GetUserAvatar) // //v1UserGroup.GET("/avatar", v1.GetUserAvatar)
v1UsersGroup.DELETE("/:id", v1.DeleteUser) // v1UsersGroup.DELETE("/:id", v1.DeleteUser)
v1UsersGroup.GET("/:username", v1.GetUserInfoByUsername) // v1UsersGroup.GET("/:username", v1.GetUserInfoByUsername)
v1UsersGroup.DELETE("", v1.DeleteUserAll) // v1UsersGroup.DELETE("", v1.DeleteUserAll)
} // }
v1AppsGroup := v1Group.Group("/apps") v1AppsGroup := v1Group.Group("/apps")
v1AppsGroup.Use() v1AppsGroup.Use()
@ -141,8 +136,9 @@ func InitRouter() *gin.Engine {
v1SysGroup.GET("/server-info", nil) v1SysGroup.GET("/server-info", nil)
v1SysGroup.PUT("/server-info", nil) v1SysGroup.PUT("/server-info", nil)
v1SysGroup.GET("/apps-state", v1.GetSystemAppsStatus) v1SysGroup.GET("/apps-state", v1.GetSystemAppsStatus)
v1SysGroup.GET("/port", v1.GetCasaOSPort) //v1SysGroup.GET("/port", v1.GetCasaOSPort)
v1SysGroup.PUT("/port", v1.PutCasaOSPort) //v1SysGroup.PUT("/port", v1.PutCasaOSPort)
v1SysGroup.GET("/proxy", v1.GetSystemProxy)
} }
v1PortGroup := v1Group.Group("/port") v1PortGroup := v1Group.Group("/port")
v1PortGroup.Use() v1PortGroup.Use()

View file

@ -1,25 +0,0 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-06-23 17:27:43
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-23 17:27:48
* @FilePath: /CasaOS/route/ui.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package route
import (
"html/template"
"github.com/IceWhaleTech/CasaOS/web"
"github.com/gin-gonic/gin"
)
func WebUIHome(c *gin.Context) {
c.Writer.Header().Set("Content-Type", "text/html; charset=utf-8")
index, _ := template.ParseFS(web.Static, "index.html")
index.Execute(c.Writer, nil)
return
}

View file

@ -14,6 +14,8 @@ import (
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err" "github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/IceWhaleTech/CasaOS/pkg/utils/encryption" "github.com/IceWhaleTech/CasaOS/pkg/utils/encryption"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS-Common/utils/jwt"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model" model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -229,7 +231,6 @@ func GetDisksUSBList(c *gin.Context) {
} }
func DeleteDisksUmount(c *gin.Context) { func DeleteDisksUmount(c *gin.Context) {
id := c.GetHeader("user_id")
js := make(map[string]string) js := make(map[string]string)
c.ShouldBind(&js) c.ShouldBind(&js)
@ -240,12 +241,17 @@ func DeleteDisksUmount(c *gin.Context) {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return return
} }
user := service.MyService.User().GetUserAllInfoById(id) token := c.GetHeader("Authorization")
if user.Id == 0 { if len(token) == 0 {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)}) token = c.Query("token")
}
claims, err := jwt.ParseToken(token, true)
if err != nil {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return return
} }
if encryption.GetMD5ByStr(pwd) != user.Password {
if encryption.GetMD5ByStr(pwd) != claims.Password {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return return
} }
@ -471,19 +477,23 @@ func PostDiskAddPartition(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /disk/format [post] // @Router /disk/format [post]
func PostDiskFormat(c *gin.Context) { func PostDiskFormat(c *gin.Context) {
id := c.GetHeader("user_id")
js := make(map[string]string) js := make(map[string]string)
c.ShouldBind(&js) c.ShouldBind(&js)
path := js["path"] path := js["path"]
t := "ext4" t := "ext4"
pwd := js["password"] pwd := js["password"]
volume := js["volume"] volume := js["volume"]
user := service.MyService.User().GetUserAllInfoById(id) token := c.GetHeader("Authorization")
if user.Id == 0 { if len(token) == 0 {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)}) token = c.Query("token")
}
claims, err := jwt.ParseToken(token, true)
if err != nil {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return return
} }
if encryption.GetMD5ByStr(pwd) != user.Password {
if encryption.GetMD5ByStr(pwd) != claims.Password {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return return
} }
@ -521,7 +531,6 @@ func PostDiskFormat(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /disk/umount [post] // @Router /disk/umount [post]
func PostDiskUmount(c *gin.Context) { func PostDiskUmount(c *gin.Context) {
id := c.GetHeader("user_id")
js := make(map[string]string) js := make(map[string]string)
c.ShouldBind(&js) c.ShouldBind(&js)
@ -533,12 +542,17 @@ func PostDiskUmount(c *gin.Context) {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return return
} }
user := service.MyService.User().GetUserAllInfoById(id) token := c.GetHeader("Authorization")
if user.Id == 0 { if len(token) == 0 {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)}) token = c.Query("token")
}
claims, err := jwt.ParseToken(token, true)
if err != nil {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return return
} }
if encryption.GetMD5ByStr(pwd) != user.Password {
if encryption.GetMD5ByStr(pwd) != claims.Password {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return return
} }

View file

@ -1,7 +1,10 @@
package v1 package v1
import ( import (
"bytes"
"fmt" "fmt"
"io"
"io/ioutil"
"net/http" "net/http"
"os" "os"
"reflect" "reflect"
@ -418,6 +421,9 @@ func GetSystemUtilization(c *gin.Context) {
cpuData := make(map[string]interface{}) cpuData := make(map[string]interface{})
cpuData["percent"] = cpu cpuData["percent"] = cpu
cpuData["num"] = num cpuData["num"] = num
cpuData["temperature"] = service.MyService.System().GetCPUTemperature()
cpuData["power"] = service.MyService.System().GetCPUPower()
data["cpu"] = cpuData data["cpu"] = cpuData
data["mem"] = service.MyService.System().GetMemInfo() data["mem"] = service.MyService.System().GetMemInfo()
@ -525,3 +531,21 @@ func GetSystemNetInfo(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: newNet}) c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: newNet})
} }
func GetSystemProxy(c *gin.Context) {
url := c.Query("url")
resp, err := http.Get(url)
if err != nil {
return
}
defer resp.Body.Close()
for k, v := range c.Request.Header {
c.Header(k, v[0])
}
rda, _ := ioutil.ReadAll(resp.Body)
// json.NewEncoder(c.Writer).Encode(json.RawMessage(string(rda)))
// 响应状态码
c.Writer.WriteHeader(resp.StatusCode)
// 复制转发的响应Body到响应Body
io.Copy(c.Writer, ioutil.NopCloser(bytes.NewBuffer(rda)))
}

View file

@ -1,683 +0,0 @@
package v1
import (
json2 "encoding/json"
"io/ioutil"
"net/http"
url2 "net/url"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/model/system_model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/IceWhaleTech/CasaOS/pkg/utils/encryption"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/jwt"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
uuid "github.com/satori/go.uuid"
"github.com/tidwall/gjson"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/gin-gonic/gin"
)
// @Summary register user
// @Router /user/register/ [post]
func PostUserRegister(c *gin.Context) {
json := make(map[string]string)
c.ShouldBind(&json)
username := json["username"]
pwd := json["password"]
key := json["key"]
if _, ok := service.UserRegisterHash[key]; !ok {
c.JSON(common_err.CLIENT_ERROR,
model.Result{Success: common_err.KEY_NOT_EXIST, Message: common_err.GetMsg(common_err.KEY_NOT_EXIST)})
return
}
if len(username) == 0 || len(pwd) == 0 {
c.JSON(common_err.CLIENT_ERROR,
model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if len(pwd) < 6 {
c.JSON(common_err.CLIENT_ERROR,
model.Result{Success: common_err.PWD_IS_TOO_SIMPLE, Message: common_err.GetMsg(common_err.PWD_IS_TOO_SIMPLE)})
return
}
oldUser := service.MyService.User().GetUserInfoByUserName(username)
if oldUser.Id > 0 {
c.JSON(common_err.CLIENT_ERROR,
model.Result{Success: common_err.USER_EXIST, Message: common_err.GetMsg(common_err.USER_EXIST)})
return
}
user := model2.UserDBModel{}
user.Username = username
user.Password = encryption.GetMD5ByStr(pwd)
user.Role = "admin"
user = service.MyService.User().CreateUser(user)
if user.Id == 0 {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR)})
return
}
file.MkDir(config.AppInfo.UserDataPath + "/" + strconv.Itoa(user.Id))
delete(service.UserRegisterHash, key)
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary login
// @Produce application/json
// @Accept application/json
// @Tags user
// @Param user_name query string true "User name"
// @Param pwd query string true "password"
// @Success 200 {string} string "ok"
// @Router /user/login [post]
func PostUserLogin(c *gin.Context) {
json := make(map[string]string)
c.ShouldBind(&json)
username := json["username"]
password := json["password"]
//check params is empty
if len(username) == 0 || len(password) == 0 {
c.JSON(common_err.CLIENT_ERROR,
model.Result{
Success: common_err.CLIENT_ERROR,
Message: common_err.GetMsg(common_err.INVALID_PARAMS),
})
return
}
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)})
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)})
return
}
token := system_model.VerifyInformation{}
token.AccessToken = jwt.GetAccessToken(user.Username, user.Password, user.Id)
token.RefreshToken = jwt.GetRefreshToken(user.Username, user.Password, user.Id)
token.ExpiresAt = time.Now().Add(3 * time.Hour * time.Duration(1)).Unix()
data := make(map[string]interface{}, 2)
user.Password = ""
data["token"] = token
// TODO:1 Database fields cannot be external
data["user"] = user
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: data,
})
}
// @Summary edit user head
// @Produce application/json
// @Accept multipart/form-data
// @Tags user
// @Param file formData file true "用户头像"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/avatar [put]
func PutUserAvatar(c *gin.Context) {
id := c.GetHeader("user_id")
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)})
return
}
f, err := c.FormFile("file")
if err != nil {
c.JSON(common_err.CLIENT_ERROR,
model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()})
return
}
if len(user.Avatar) > 0 {
os.RemoveAll(config.AppInfo.UserDataPath + "/" + id + "/" + user.Avatar)
}
ext := filepath.Ext(f.Filename)
avatarPath := config.AppInfo.UserDataPath + "/" + id + "/avatar" + ext
c.SaveUploadedFile(f, avatarPath)
user.Avatar = avatarPath
service.MyService.User().UpdateUser(user)
c.JSON(http.StatusOK,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: user,
})
}
// @Summary edit user name
// @Produce application/json
// @Accept application/json
// @Tags user
// @Param old_name query string true "Old user name"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/name/:id [put]
func PutUserInfo(c *gin.Context) {
id := c.GetHeader("user_id")
json := model2.UserDBModel{}
c.ShouldBind(&json)
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)})
return
}
if len(json.Username) > 0 {
u := service.MyService.User().GetUserInfoByUserName(json.Username)
if u.Id > 0 {
c.JSON(common_err.CLIENT_ERROR,
model.Result{Success: common_err.USER_EXIST, Message: common_err.GetMsg(common_err.USER_EXIST)})
return
}
}
if len(json.Email) == 0 {
json.Email = user.Email
}
if len(json.Avatar) == 0 {
json.Avatar = user.Avatar
}
if len(json.Role) == 0 {
json.Role = user.Role
}
if len(json.Description) == 0 {
json.Description = user.Description
}
if len(json.Nickname) == 0 {
json.Nickname = user.Nickname
}
service.MyService.User().UpdateUser(json)
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: json})
}
// @Summary edit user password
// @Produce application/json
// @Accept application/json
// @Tags user
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/password/:id [put]
func PutUserPassword(c *gin.Context) {
id := c.GetHeader("user_id")
json := make(map[string]string)
c.ShouldBind(&json)
oldPwd := json["old_password"]
pwd := json["password"]
if len(oldPwd) == 0 || len(pwd) == 0 {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
user := service.MyService.User().GetUserAllInfoById(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)})
return
}
if user.Password != encryption.GetMD5ByStr(oldPwd) {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID_OLD, Message: common_err.GetMsg(common_err.PWD_INVALID_OLD)})
return
}
user.Password = encryption.GetMD5ByStr(pwd)
service.MyService.User().UpdateUserPassword(user)
user.Password = ""
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: user})
}
// @Summary edit user nick
// @Produce application/json
// @Accept application/json
// @Tags user
// @Param nick_name query string false "nick name"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/nick [put]
func PutUserNick(c *gin.Context) {
id := c.GetHeader("user_id")
json := make(map[string]string)
c.ShouldBind(&json)
Nickname := json["nick_name"]
if len(Nickname) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
user := service.MyService.User().GetUserInfoById(id)
if user.Id == 0 {
c.JSON(http.StatusOK,
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
user.Nickname = Nickname
service.MyService.User().UpdateUser(user)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: user})
}
// @Summary edit user description
// @Produce application/json
// @Accept multipart/form-data
// @Tags user
// @Param description formData string false "Description"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/desc [put]
func PutUserDesc(c *gin.Context) {
id := c.GetHeader("user_id")
json := make(map[string]string)
c.ShouldBind(&json)
desc := json["description"]
if len(desc) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
user := service.MyService.User().GetUserInfoById(id)
if user.Id == 0 {
c.JSON(http.StatusOK,
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
user.Description = desc
service.MyService.User().UpdateUser(user)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: user})
}
// @Summary get user info
// @Produce application/json
// @Accept application/json
// @Tags user
// @Success 200 {string} string "ok"
// @Router /user/info/:id [get]
func GetUserInfo(c *gin.Context) {
id := c.GetHeader("user_id")
user := service.MyService.User().GetUserInfoById(id)
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: user,
})
}
/**
* @description:
* @param {*gin.Context} c
* @param {string} Username
* @return {*}
* @method:
* @router:
*/
func GetUserInfoByUsername(c *gin.Context) {
username := c.Param("username")
if len(username) == 0 {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
user := service.MyService.User().GetUserInfoByUserName(username)
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)})
return
}
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: user,
})
}
/**
* @description: get all Usernames
* @method:GET
* @router:/user/all/name
*/
func GetUserAllUsername(c *gin.Context) {
users := service.MyService.User().GetAllUserName()
names := []string{}
for _, v := range users {
names = append(names, v.Username)
}
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: names,
})
}
/**
* @description:get custom file by user
* @param {path} name string "file name"
* @method: GET
* @router: /user/custom/:key
*/
func GetUserCustomConf(c *gin.Context) {
name := c.Param("key")
if len(name) == 0 {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
id := c.GetHeader("user_id")
user := service.MyService.User().GetUserInfoById(id)
// user := service.MyService.User().GetUserInfoByUsername(Username)
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)})
return
}
filePath := config.AppInfo.UserDataPath + "/" + id + "/" + name + ".json"
data := file.ReadFullFile(filePath)
if !gjson.ValidBytes(data) {
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: string(data)})
return
}
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: json2.RawMessage(string(data))})
}
/**
* @description:create or update custom conf by user
* @param {path} name string "file name"
* @method:POST
* @router:/user/custom/:key
*/
func PostUserCustomConf(c *gin.Context) {
name := c.Param("key")
if len(name) == 0 {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
id := c.GetHeader("user_id")
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)})
return
}
data, _ := ioutil.ReadAll(c.Request.Body)
filePath := config.AppInfo.UserDataPath + "/" + strconv.Itoa(user.Id)
file.WriteToPath(data, filePath, name+".json")
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: json2.RawMessage(string(data))})
}
/**
* @description: delete user custom config
* @param {path} key string
* @method:delete
* @router:/user/custom/:key
*/
func DeleteUserCustomConf(c *gin.Context) {
name := c.Param("key")
if len(name) == 0 {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
id := c.GetHeader("user_id")
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)})
return
}
filePath := config.AppInfo.UserDataPath + "/" + strconv.Itoa(user.Id) + "/" + name + ".json"
err := os.Remove(filePath)
if err != nil {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR)})
return
}
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
/**
* @description:
* @param {path} id string "user id"
* @method:DELETE
* @router:/user/delete/:id
*/
func DeleteUser(c *gin.Context) {
id := c.Param("id")
service.MyService.User().DeleteUserById(id)
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: id})
}
/**
* @description:update user image
* @method:POST
* @router:/user/current/image/:key
*/
func PutUserImage(c *gin.Context) {
id := c.GetHeader("user_id")
json := make(map[string]string)
c.ShouldBind(&json)
path := json["path"]
key := c.Param("key")
if len(path) == 0 || len(key) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if !file.Exists(path) {
c.JSON(http.StatusOK, model.Result{Success: common_err.FILE_DOES_NOT_EXIST, Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST)})
return
}
_, err := file.GetImageExt(path)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.NOT_IMAGE, Message: common_err.GetMsg(common_err.NOT_IMAGE)})
return
}
user := service.MyService.User().GetUserInfoById(id)
if user.Id == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
fstat, _ := os.Stat(path)
if fstat.Size() > 10<<20 {
c.JSON(http.StatusOK, model.Result{Success: common_err.IMAGE_TOO_LARGE, Message: common_err.GetMsg(common_err.IMAGE_TOO_LARGE)})
return
}
ext := file.GetExt(path)
filePath := config.AppInfo.UserDataPath + "/" + strconv.Itoa(user.Id) + "/" + key + ext
file.CopySingleFile(path, filePath, "overwrite")
data := make(map[string]string, 3)
data["path"] = filePath
data["file_name"] = key + ext
data["online_path"] = "/v1/users/image?path=" + filePath
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}
/**
* @description:
* @param {*gin.Context} c
* @param {file} file
* @param {string} key
* @param {string} type:avatar,background
* @return {*}
* @method:
* @router:
*/
func PostUserUploadImage(c *gin.Context) {
id := c.GetHeader("user_id")
f, err := c.FormFile("file")
key := c.Param("key")
t := c.PostForm("type")
if len(key) == 0 {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if err != nil {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()})
return
}
_, err = file.GetImageExtByName(f.Filename)
if err != nil {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.NOT_IMAGE, Message: common_err.GetMsg(common_err.NOT_IMAGE)})
return
}
ext := filepath.Ext(f.Filename)
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)})
return
}
if t == "avatar" {
key = "avatar"
}
path := config.AppInfo.UserDataPath + "/" + strconv.Itoa(user.Id) + "/" + key + ext
c.SaveUploadedFile(f, path)
data := make(map[string]string, 3)
data["path"] = path
data["file_name"] = key + ext
data["online_path"] = "/v1/users/image?path=" + path
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}
/**
* @description: get current user's image
* @method:GET
* @router:/user/image/:id
*/
func GetUserImage(c *gin.Context) {
filePath := c.Query("path")
if len(filePath) == 0 {
c.JSON(http.StatusNotFound, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if !file.Exists(filePath) {
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) {
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()
fileName := path.Base(filePath)
// @tiger - RESTful 规范下不应该返回文件本身内容而是返回文件的静态URL由前端去解析
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
c.File(filePath)
}
func DeleteUserImage(c *gin.Context) {
id := c.GetHeader("user_id")
path := c.Query("path")
if len(path) == 0 {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
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)})
return
}
if !file.Exists(path) {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_DOES_NOT_EXIST, Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST)})
return
}
if !strings.Contains(path, config.AppInfo.UserDataPath+"/"+strconv.Itoa(user.Id)) {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)})
return
}
os.Remove(path)
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
/**
* @description:
* @param {*gin.Context} c
* @param {string} refresh_token
* @return {*}
* @method:
* @router:
*/
func PostUserRefreshToken(c *gin.Context) {
js := make(map[string]string)
c.ShouldBind(&js)
refresh := js["refresh_token"]
claims, err := jwt.ParseToken(refresh, true)
if err != nil {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.VERIFICATION_FAILURE, Message: common_err.GetMsg(common_err.VERIFICATION_FAILURE), Data: err.Error()})
return
}
if !claims.VerifyExpiresAt(time.Now(), true) || !claims.VerifyIssuer("refresh", true) {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.VERIFICATION_FAILURE, Message: common_err.GetMsg(common_err.VERIFICATION_FAILURE)})
return
}
newToken := jwt.GetAccessToken(claims.Username, claims.PassWord, claims.Id)
verifyInfo := system_model.VerifyInformation{}
verifyInfo.AccessToken = newToken
verifyInfo.RefreshToken = jwt.GetRefreshToken(claims.Username, claims.PassWord, claims.Id)
verifyInfo.ExpiresAt = time.Now().Add(3 * time.Hour * time.Duration(1)).Unix()
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: verifyInfo})
}
func DeleteUserAll(c *gin.Context) {
service.MyService.User().DeleteAllUser()
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary 检查是否进入引导状态
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/init/check [get]
func GetUserStatus(c *gin.Context) {
data := make(map[string]interface{}, 2)
if service.MyService.User().GetUserCount() > 0 {
data["initialized"] = true
data["key"] = ""
} else {
key := uuid.NewV4().String()
service.UserRegisterHash[key] = key
data["key"] = key
data["initialized"] = false
}
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: data,
})
}

View file

@ -439,7 +439,7 @@ func (a *appStruct) GetHardwareUsageStream() {
wg.Add(1) wg.Add(1)
go func(v types.Container, i int) { go func(v types.Container, i int) {
defer wg.Done() defer wg.Done()
stats, err := cli.ContainerStats(ctx, v.ID, true) stats, err := cli.ContainerStatsOneShot(ctx, v.ID)
if err != nil { if err != nil {
return return
} }

View file

@ -144,7 +144,7 @@ func (o *casaService) AsyncGetServerList() (collection model.ServerAppListCollec
listModel := []model.ServerAppList{} listModel := []model.ServerAppList{}
communityModel := []model.ServerAppList{} communityModel := []model.ServerAppList{}
recommendModel := []model.ServerAppList{} recommendModel := []model.ServerAppList{}
json2.Unmarshal([]byte(gjson.Get(listS, "data.list").String()), &listModel) err = json2.Unmarshal([]byte(gjson.Get(listS, "data.list").String()), &listModel)
json2.Unmarshal([]byte(gjson.Get(listS, "data.recommend").String()), &recommendModel) json2.Unmarshal([]byte(gjson.Get(listS, "data.recommend").String()), &recommendModel)
json2.Unmarshal([]byte(gjson.Get(listS, "data.community").String()), &communityModel) json2.Unmarshal([]byte(gjson.Get(listS, "data.community").String()), &communityModel)

View file

@ -7,13 +7,8 @@ import (
"encoding/binary" "encoding/binary"
json2 "encoding/json" json2 "encoding/json"
"fmt" "fmt"
"syscall"
"github.com/IceWhaleTech/CasaOS/model/notify" "github.com/IceWhaleTech/CasaOS/model/notify"
"github.com/containerd/containerd"
"github.com/containerd/containerd/cio"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/oci"
"github.com/pkg/errors" "github.com/pkg/errors"
"go.uber.org/zap" "go.uber.org/zap"
@ -535,6 +530,13 @@ func (ds *dockerService) DockerContainerCreate(m model.CustomizationPostData, id
// info.NetworkSettings = &types.NetworkSettings{} // info.NetworkSettings = &types.NetworkSettings{}
hostConfig = info.HostConfig hostConfig = info.HostConfig
config = info.Config config = info.Config
if config.Labels["casaos"] == "casaos" {
config.Cmd = m.Cmd
config.Image = m.Image
config.Env = envArr
config.Hostname = m.HostName
config.ExposedPorts = ports
}
} else { } else {
config.Cmd = m.Cmd config.Cmd = m.Cmd
config.Image = m.Image config.Image = m.Image
@ -872,73 +874,73 @@ func NewDockerService() DockerService {
// //
//} //}
func Containerd() { // func Containerd() {
// create a new client connected to the default socket path for containerd // // create a new client connected to the default socket path for containerd
cli, err := containerd.New("/run/containerd/containerd.sock") // cli, err := containerd.New("/run/containerd/containerd.sock")
if err != nil { // if err != nil {
fmt.Println("111") // fmt.Println("111")
fmt.Println(err) // fmt.Println(err)
} // }
defer cli.Close() // defer cli.Close()
// create a new context with an "example" namespace // // create a new context with an "example" namespace
ctx := namespaces.WithNamespace(context.Background(), "default") // ctx := namespaces.WithNamespace(context.Background(), "default")
// pull the redis image from DockerHub // // pull the redis image from DockerHub
image, err := cli.Pull(ctx, "docker.io/library/busybox:latest", containerd.WithPullUnpack) // image, err := cli.Pull(ctx, "docker.io/library/busybox:latest", containerd.WithPullUnpack)
if err != nil { // if err != nil {
fmt.Println("222") // fmt.Println("222")
fmt.Println(err) // fmt.Println(err)
} // }
// create a container // // create a container
container, err := cli.NewContainer( // container, err := cli.NewContainer(
ctx, // ctx,
"test1", // "test1",
containerd.WithImage(image), // containerd.WithImage(image),
containerd.WithNewSnapshot("redis-server-snapshot1", image), // containerd.WithNewSnapshot("redis-server-snapshot1", image),
containerd.WithNewSpec(oci.WithImageConfig(image)), // containerd.WithNewSpec(oci.WithImageConfig(image)),
) // )
if err != nil { // if err != nil {
fmt.Println(err) // fmt.Println(err)
} // }
defer container.Delete(ctx, containerd.WithSnapshotCleanup) // defer container.Delete(ctx, containerd.WithSnapshotCleanup)
// create a task from the container // // create a task from the container
task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio)) // task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio))
if err != nil { // if err != nil {
fmt.Println(err) // fmt.Println(err)
} // }
defer task.Delete(ctx) // defer task.Delete(ctx)
// make sure we wait before calling start // // make sure we wait before calling start
exitStatusC, err := task.Wait(ctx) // exitStatusC, err := task.Wait(ctx)
if err != nil { // if err != nil {
fmt.Println(err) // fmt.Println(err)
} // }
// call start on the task to execute the redis server // // call start on the task to execute the redis server
if err = task.Start(ctx); err != nil { // if err = task.Start(ctx); err != nil {
fmt.Println(err) // fmt.Println(err)
} // }
fmt.Println("执行完成等待") // fmt.Println("执行完成等待")
// sleep for a lil bit to see the logs // // sleep for a lil bit to see the logs
time.Sleep(3 * time.Second) // time.Sleep(3 * time.Second)
// kill the process and get the exit status // // kill the process and get the exit status
if err = task.Kill(ctx, syscall.SIGTERM); err != nil { // if err = task.Kill(ctx, syscall.SIGTERM); err != nil {
fmt.Println(err) // fmt.Println(err)
} // }
// wait for the process to fully exit and print out the exit status // // wait for the process to fully exit and print out the exit status
status := <-exitStatusC // status := <-exitStatusC
code, _, err := status.Result() // code, _, err := status.Result()
if err != nil { // if err != nil {
fmt.Println(err) // fmt.Println(err)
} // }
fmt.Printf("redis-server exited with status: %d\n", code) // fmt.Printf("redis-server exited with status: %d\n", code)
} // }

View file

@ -1,31 +0,0 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-11 17:57:00
* @FilePath: /CasaOS/service/model/o_user.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package model
import "time"
//Soon to be removed
type UserDBModel struct {
Id int `gorm:"column:id;primary_key" json:"id"`
Username string `json:"username"`
Password string `json:"password,omitempty"`
Role string `json:"role"`
Email string `json:"email"`
Nickname string `json:"nickname"`
Avatar string `json:"avatar"`
Description string `json:"description"`
CreatedAt time.Time `gorm:"<-:create;autoCreateTime" json:"created_at,omitempty"`
UpdatedAt time.Time `gorm:"<-:create;<-:update;autoUpdateTime" json:"updated_at,omitempty"`
}
func (p *UserDBModel) TableName() string {
return "o_users"
}

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com * @Author: LinkLeong link@icewhale.com
* @Date: 2022-07-12 09:48:56 * @Date: 2022-07-12 09:48:56
* @LastEditors: LinkLeong * @LastEditors: LinkLeong
* @LastEditTime: 2022-07-27 10:28:48 * @LastEditTime: 2022-09-02 22:10:05
* @FilePath: /CasaOS/service/service.go * @FilePath: /CasaOS/service/service.go
* @Description: * @Description:
* @Website: https://www.casaos.io * @Website: https://www.casaos.io
@ -11,6 +11,7 @@
package service package service
import ( import (
gateway "github.com/IceWhaleTech/CasaOS-Gateway/common"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/patrickmn/go-cache" "github.com/patrickmn/go-cache"
"gorm.io/gorm" "gorm.io/gorm"
@ -26,7 +27,7 @@ var SocketRun bool
type Repository interface { type Repository interface {
App() AppService App() AppService
User() UserService //User() UserService
Docker() DockerService Docker() DockerService
Casa() CasaService Casa() CasaService
Disk() DiskService Disk() DiskService
@ -35,12 +36,19 @@ type Repository interface {
System() SystemService System() SystemService
Shares() SharesService Shares() SharesService
Connections() ConnectionsService Connections() ConnectionsService
Gateway() gateway.ManagementService
} }
func NewService(db *gorm.DB) Repository { func NewService(db *gorm.DB, RuntimePath string) Repository {
gatewayManagement, err := gateway.NewManagementService(RuntimePath)
if err != nil && len(RuntimePath) > 0 {
panic(err)
}
return &store{ return &store{
gateway: gatewayManagement,
app: NewAppService(db), app: NewAppService(db),
user: NewUserService(db),
docker: NewDockerService(), docker: NewDockerService(),
casa: NewCasaService(), casa: NewCasaService(),
disk: NewDiskService(db), disk: NewDiskService(db),
@ -55,7 +63,6 @@ func NewService(db *gorm.DB) Repository {
type store struct { type store struct {
db *gorm.DB db *gorm.DB
app AppService app AppService
user UserService
docker DockerService docker DockerService
casa CasaService casa CasaService
disk DiskService disk DiskService
@ -64,8 +71,12 @@ type store struct {
system SystemService system SystemService
shares SharesService shares SharesService
connections ConnectionsService connections ConnectionsService
gateway gateway.ManagementService
} }
func (c *store) Gateway() gateway.ManagementService {
return c.gateway
}
func (s *store) Connections() ConnectionsService { func (s *store) Connections() ConnectionsService {
return s.connections return s.connections
} }
@ -89,10 +100,6 @@ func (c *store) App() AppService {
return c.app return c.app
} }
func (c *store) User() UserService {
return c.user
}
func (c *store) Docker() DockerService { func (c *store) Docker() DockerService {
return c.docker return c.docker
} }

View file

@ -50,6 +50,8 @@ type SystemService interface {
RenameFile(oldF, newF string) (int, error) RenameFile(oldF, newF string) (int, error)
MkdirAll(path string) (int, error) MkdirAll(path string) (int, error)
IsServiceRunning(name string) bool IsServiceRunning(name string) bool
GetCPUTemperature() int
GetCPUPower() map[string]string
} }
type systemService struct { type systemService struct {
} }
@ -219,7 +221,7 @@ func (s *systemService) UpdateSystemVersion(version string) {
} }
file.CreateFile(config.AppInfo.LogPath + "/upgrade.log") file.CreateFile(config.AppInfo.LogPath + "/upgrade.log")
//go command2.OnlyExec("curl -fsSL https://raw.githubusercontent.com/LinkLeong/casaos-alpha/main/update.sh | bash") //go command2.OnlyExec("curl -fsSL https://raw.githubusercontent.com/LinkLeong/casaos-alpha/main/update.sh | bash")
go command2.OnlyExec("curl -fsSL https://raw.githubusercontent.com/IceWhaleTech/get/main/update.sh | bash") go command2.OnlyExec("curl -fsSL https://raw.githubusercontent.com/IceWhaleTech/get/main/update.sh | sudo bash")
//s.log.Error(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version) //s.log.Error(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version)
//s.log.Error(command2.ExecResultStr(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version)) //s.log.Error(command2.ExecResultStr(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version))
} }
@ -294,6 +296,33 @@ func (s *systemService) IsServiceRunning(name string) bool {
return strings.TrimSpace(status) == "running" return strings.TrimSpace(status) == "running"
} }
func (s *systemService) GetCPUTemperature() int {
outPut := ""
if file.Exists("/sys/class/thermal/thermal_zone0/temp") {
outPut = string(file.ReadFullFile("/sys/class/thermal/thermal_zone0/temp"))
} else if file.Exists("/sys/class/hwmon/hwmon0/temp1_input") {
outPut = string(file.ReadFullFile("/sys/class/hwmon/hwmon0/temp1_input"))
} else {
outPut = "0"
}
celsius, _ := strconv.Atoi(strings.TrimSpace(outPut))
if celsius > 1000 {
celsius = celsius / 1000
}
return celsius
}
func (s *systemService) GetCPUPower() map[string]string {
data := make(map[string]string, 2)
data["timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
if file.Exists("/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj") {
data["value"] = strings.TrimSpace(string(file.ReadFullFile("/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj")))
} else {
data["value"] = "0"
}
return data
}
func NewSystemService() SystemService { func NewSystemService() SystemService {
return &systemService{} return &systemService{}
} }

View file

@ -1,99 +0,0 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-03-18 11:40:55
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-12 10:05:37
* @FilePath: /CasaOS/service/user.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package service
import (
"io"
"mime/multipart"
"os"
"github.com/IceWhaleTech/CasaOS/service/model"
"gorm.io/gorm"
)
type UserService interface {
UpLoadFile(file multipart.File, name string) error
CreateUser(m model.UserDBModel) model.UserDBModel
GetUserCount() (userCount int64)
UpdateUser(m model.UserDBModel)
UpdateUserPassword(m model.UserDBModel)
GetUserInfoById(id string) (m model.UserDBModel)
GetUserAllInfoById(id string) (m model.UserDBModel)
GetUserAllInfoByName(userName string) (m model.UserDBModel)
DeleteUserById(id string)
DeleteAllUser()
GetUserInfoByUserName(userName string) (m model.UserDBModel)
GetAllUserName() (list []model.UserDBModel)
}
var UserRegisterHash = make(map[string]string)
type userService struct {
db *gorm.DB
}
func (u *userService) DeleteAllUser() {
u.db.Where("1=1").Delete(&model.UserDBModel{})
}
func (u *userService) DeleteUserById(id string) {
u.db.Where("id= ?", id).Delete(&model.UserDBModel{})
}
func (u *userService) GetAllUserName() (list []model.UserDBModel) {
u.db.Select("username").Find(&list)
return
}
func (u *userService) CreateUser(m model.UserDBModel) model.UserDBModel {
u.db.Create(&m)
return m
}
func (u *userService) GetUserCount() (userCount int64) {
u.db.Find(&model.UserDBModel{}).Count(&userCount)
return
}
func (u *userService) UpdateUser(m model.UserDBModel) {
u.db.Model(&m).Omit("password").Updates(&m)
}
func (u *userService) UpdateUserPassword(m model.UserDBModel) {
u.db.Model(&m).Update("password", m.Password)
}
func (u *userService) GetUserAllInfoById(id string) (m model.UserDBModel) {
u.db.Where("id= ?", id).First(&m)
return
}
func (u *userService) GetUserAllInfoByName(userName string) (m model.UserDBModel) {
u.db.Where("username= ?", userName).First(&m)
return
}
func (u *userService) GetUserInfoById(id string) (m model.UserDBModel) {
u.db.Select("username", "id", "role", "nickname", "description", "avatar", "email").Where("id= ?", id).First(&m)
return
}
func (u *userService) GetUserInfoByUserName(userName string) (m model.UserDBModel) {
u.db.Select("username", "id", "role", "nickname", "description", "avatar", "email").Where("username= ?", userName).First(&m)
return
}
//上传文件
func (c *userService) UpLoadFile(file multipart.File, url string) error {
out, _ := os.OpenFile(url, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
defer out.Close()
io.Copy(out, file)
return nil
}
//获取用户Service
func NewUserService(db *gorm.DB) UserService {
return &userService{db: db}
}

View file

@ -1,6 +0,0 @@
# copy to /etc/udev/rules.d path
KERNEL=="sd[a-z]*[0-9]", SUBSYSTEMS=="usb", ACTION=="add", RUN+="/bin/systemctl start usb-mount@%k.service"
KERNEL=="sd[a-z]*[0-9]", SUBSYSTEMS=="usb", ACTION=="remove", RUN+="/bin/systemctl stop usb-mount@%k.service"

View file

@ -1,3 +0,0 @@
#!/bin/bash

View file

@ -1,105 +0,0 @@
#!/bin/bash
###
# @Author: LinkLeong link@icewhale.com
# @Date: 2022-06-30 10:08:33
# @LastEditors: LinkLeong
# @LastEditTime: 2022-07-01 11:17:54
# @FilePath: /CasaOS/shell/delete-old-service.sh
# @Description:
###
((EUID)) && sudo_cmd="sudo"
# SYSTEM INFO
readonly UNAME_M="$(uname -m)"
# CasaOS PATHS
readonly CASA_REPO=IceWhaleTech/CasaOS
readonly CASA_UNZIP_TEMP_FOLDER=/tmp/casaos
readonly CASA_BIN=casaos
readonly CASA_BIN_PATH=/usr/bin/casaos
readonly CASA_CONF_PATH=/etc/casaos.conf
readonly CASA_SERVICE_PATH=/etc/systemd/system/casaos.service
readonly CASA_HELPER_PATH=/usr/share/casaos/shell/
readonly CASA_USER_CONF_PATH=/var/lib/casaos/conf/
readonly CASA_DB_PATH=/var/lib/casaos/db/
readonly CASA_TEMP_PATH=/var/lib/casaos/temp/
readonly CASA_LOGS_PATH=/var/log/casaos/
readonly CASA_PACKAGE_EXT=".tar.gz"
readonly CASA_RELEASE_API="https://api.github.com/repos/${CASA_REPO}/releases"
readonly CASA_OPENWRT_DOCS="https://github.com/IceWhaleTech/CasaOS-OpenWrt"
readonly COLOUR_RESET='\e[0m'
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
)
Target_Arch=""
Target_Distro="debian"
Target_OS="linux"
Casa_Tag=""
#######################################
# Custom printing function
# Globals:
# None
# Arguments:
# $1 0:OK 1:FAILED 2:INFO 3:NOTICE
# message
# Returns:
# None
#######################################
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"
}
# 0 Check_exist
Check_Exist() {
#Create Dir
Show 2 "Create Folders."
${sudo_cmd} mkdir -p ${CASA_HELPER_PATH}
${sudo_cmd} mkdir -p ${CASA_LOGS_PATH}
${sudo_cmd} mkdir -p ${CASA_USER_CONF_PATH}
${sudo_cmd} mkdir -p ${CASA_DB_PATH}
${sudo_cmd} mkdir -p ${CASA_TEMP_PATH}
Show 2 "Start cleaning up the old version."
${sudo_cmd} rm -rf /usr/lib/systemd/system/casaos.service
${sudo_cmd} rm -rf /lib/systemd/system/casaos.service
${sudo_cmd} rm -rf /usr/local/bin/${CASA_BIN}
#Clean
if [[ -d "/casaOS" ]]; then
${sudo_cmd} rm -rf /casaOS
fi
Show 0 "Clearance completed."
$sudo_cmd systemctl restart ${CASA_BIN}
}
Check_Exist

View file

@ -1,389 +0,0 @@
#!/bin/bash
# 获取系统信息
GetSysInfo() {
if [ -s "/etc/redhat-release" ]; then
SYS_VERSION=$(cat /etc/redhat-release)
elif [ -s "/etc/issue" ]; then
SYS_VERSION=$(cat /etc/issue)
fi
SYS_INFO=$(uname -a)
SYS_BIT=$(getconf LONG_BIT)
MEM_TOTAL=$(free -m | grep Mem | awk '{print $2}')
CPU_INFO=$(getconf _NPROCESSORS_ONLN)
echo -e ${SYS_VERSION}
echo -e Bit:${SYS_BIT} Mem:${MEM_TOTAL}M Core:${CPU_INFO}
echo -e ${SYS_INFO}
}
#获取网卡信息
GetNetCard() {
if [ "$1" == "1" ]; then
if [ -d "/sys/devices/virtual/net" ]; then
ls /sys/devices/virtual/net
fi
else
if [ -d "/sys/devices/virtual/net" ] && [ -d "/sys/class/net" ]; then
ls /sys/class/net/ | grep -v "$(ls /sys/devices/virtual/net/)"
fi
fi
}
GetTimeZone(){
timedatectl | grep "Time zone" | awk '{printf $3}'
}
#查看网卡状态
#param 网卡名称
CatNetCardState() {
if [ -e "/sys/class/net/$1/operstate" ]; then
cat /sys/class/net/$1/operstate
fi
}
#获取docker根目录
GetDockerRootDir() {
if hash docker 2>/dev/null; then
docker info | grep 'Docker Root Dir' | awk -F ':' '{print $2}'
else
echo ""
fi
}
#删除安装应用文件夹
#param 需要删除的文件夹路径
DelAppConfigDir() {
if [ -d $1 ]; then
rm -fr $1
fi
}
#zerotier本机已加入的网络
#result start,end,sectors
GetLocalJoinNetworks() {
zerotier-cli listnetworks -j
}
#移除挂载点,删除已挂在的文件夹
UMountPorintAndRemoveDir() {
DEVICE=$1
MOUNT_POINT=$(mount | grep ${DEVICE} | awk '{ print $3 }')
if [[ -z ${MOUNT_POINT} ]]; then
${log} "Warning: ${DEVICE} is not mounted"
else
umount -lf ${DEVICE}
/bin/rmdir "${MOUNT_POINT}"
fi
}
#格式化fat32磁盘
#param 需要格式化的目录 /dev/sda1
#param 格式
FormatDisk() {
if [ "$2" == "fat32" ]; then
mkfs.vfat -F 32 $1
elif [ "$2" == "ntfs" ]; then
mkfs.ntfs $1
elif [ "$2" == "ext4" ]; then
mkfs.ext4 -m 1 -F $1
elif [ "$2" == "exfat" ]; then
mkfs.exfat $1
else
mkfs.ext4 -m 1 -F $1
fi
}
#删除分区
#param 路径 /dev/sdb
#param 删除分区的区号
DelPartition() {
fdisk $1 <<EOF
d
$2
wq
EOF
}
#添加分区只有一个分区
#param 路径 /dev/sdb
#param 要挂载的目录
AddPartition() {
DelPartition $1
parted -s $1 mklabel gpt
parted -s $1 mkpart primary ext4 0 100%
P=`lsblk -r $1 | sort | grep part | head -n 1 | awk '{print $1}'`
mkfs.ext4 -m 1 -F /dev/${P}
partprobe $1
}
#磁盘类型
GetDiskType() {
fdisk $1 -l | grep Disklabel | awk -F: '{print $2}'
}
#获磁盘的插入路径
#param 路径 /dev/sda
GetPlugInDisk() {
fdisk -l | grep 'Disk' | grep 'sd' | awk -F , '{print substr($1,11,3)}'
}
#获取磁盘状态
#param 磁盘路径
GetDiskHealthState() {
smartctl -H $1 | grep "SMART Health Status" | awk -F ":" '{print$2}'
}
#获取磁盘字节数量和扇区数量
#param 磁盘路径 /dev/sda
#result bytes
#result sectors
GetDiskSizeAndSectors() {
fdisk $1 -l | grep "$1:" | awk -F, 'BEGIN {OFS="\n"}{print $2,$3}' | awk '{print $1}'
}
#获取磁盘分区数据扇区
#param 磁盘路径 /dev/sda
#result start,end,sectors
GetPartitionSectors() {
fdisk $1 -l | grep "$1[1-9]" | awk 'BEGIN{OFS=","}{print $1,$2,$3,$4}'
}
#检查没有使用的挂载点删除文件夹
AutoRemoveUnuseDir() {
DIRECTORY="/DATA/"
dir=$(ls -l $DIRECTORY | grep "USB_Storage_sd[a-z][0-9]" | awk '/^d/ {print $NF}')
for i in $dir; do
path="$DIRECTORY$i"
mountStr=$(mountpoint $path)
notMountpoint="is not a mountpoint"
if [[ $mountStr =~ $notMountpoint ]]; then
if [ "$(ls -A $path)" = "" ]; then
rm -fr $path
else
echo "$path is not empty"
fi
fi
done
}
#重载samba服务
ReloadSamba() {
/etc/init.d/smbd reload
}
# $1=sda1
# $2=volume{1}
do_mount() {
DEVBASE=$1
DEVICE="${DEVBASE}"
# See if this drive is already mounted, and if so where
MOUNT_POINT=$(lsblk -o name,mountpoint | grep ${DEVICE} | awk '{print $2}')
if [ -n "${MOUNT_POINT}" ]; then
${log} "Warning: ${DEVICE} is already mounted at ${MOUNT_POINT}"
exit 1
fi
# Get info for this drive: $ID_FS_LABEL and $ID_FS_TYPE
eval $(blkid -o udev ${DEVICE} | grep -i -e "ID_FS_LABEL" -e "ID_FS_TYPE")
LABEL=$2
if grep -q " ${LABEL} " /etc/mtab; then
# Already in use, make a unique one
LABEL+="-${DEVBASE}"
fi
DEV_LABEL="${LABEL}"
# Use the device name in case the drive doesn't have label
if [ -z ${DEV_LABEL} ]; then
DEV_LABEL="${DEVBASE}"
fi
MOUNT_POINT="${DEV_LABEL}"
${log} "Mount point: ${MOUNT_POINT}"
mkdir -p ${MOUNT_POINT}
case ${ID_FS_TYPE} in
vfat)
mount -t vfat -o rw,relatime,users,gid=100,umask=000,shortname=mixed,utf8=1,flush ${DEVICE} ${MOUNT_POINT}
;;
ext[2-4])
mount -o noatime ${DEVICE} ${MOUNT_POINT} >/dev/null 2>&1
;;
exfat)
mount -t exfat ${DEVICE} ${MOUNT_POINT} >/dev/null 2>&1
;;
ntfs)
ntfs-3g ${DEVICE} ${MOUNT_POINT}
;;
iso9660)
mount -t iso9660 ${DEVICE} ${MOUNT_POINT}
;;
*)
/bin/rmdir "${MOUNT_POINT}"
exit 0
;;
esac
}
# $1=sda1
do_umount() {
log="logger -t usb-mount.sh -s "
DEVBASE=$1
DEVICE="${DEVBASE}"
MOUNT_POINT=$(mount | grep ${DEVICE} | awk '{ print $3 }')
if [[ -z ${MOUNT_POINT} ]]; then
${log} "Warning: ${DEVICE} is not mounted"
else
/bin/kill -9 $(lsof ${MOUNT_POINT})
umount -l ${DEVICE}
${log} "Unmounted ${DEVICE} from ${MOUNT_POINT}"
if [ "`ls -A ${MOUNT_POINT}`" = "" ]; then
/bin/rm -fr "${MOUNT_POINT}"
fi
sed -i.bak "\@${MOUNT_POINT}@d" /var/log/usb-mount.track
fi
}
# $1=/mnt/volume1/data.img
# $2=100G
PackageDocker() {
image=$1
docker="/mnt/casa_docker"
#判断目录docker存在不存在则创建,存在检查是否为空
if [ ! -d "$docker" ]; then
mkdir ${docker}
fi
if [ "$(ls -A $docker)" = "" ]; then
echo "$docker count is 0"
else
mkdir ${docker}_bak
mv -r ${docker} ${docker}_bak
fi
daemon="/etc/docker/daemon.json"
#1创建img文件在挂载的目录
fallocate -l $2 $image
#2初始化img文件
mkfs -t ext4 $image
#3挂载img文件
sudo mount -o loop $image $docker
#4给移动/var/lib/docker数据到img挂载的目录
systemctl stop docker.socket
systemctl stop docker
cp -r /var/lib/docker/* ${docker}/
#5在/etc/docker写入daemon.json(需要检查)
if [ -d "$daemon" ]; then
mv -r $daemon ${daemon}.bak
fi
echo "{\"data-root\": \"$docker\"}" >$daemon
#删除老数据腾出空间
#rm -fr /var/lib/docker
systemctl start docker.socket
systemctl start docker
}
DockerImgMove() {
image=$1
systemctl stop docker.socket
systemctl stop docker
sudo umount -f $image
}
GetDockerDataRoot() {
docker info | grep "Docker Root Dir:"
}
SetLink() {
ln -s /mnt/casa_sda1/AppData /DATA/AppData
#删除所有软链
find /DATA -type l -delete
}
#压缩文件夹
TarFolder() {
#压缩
tar -zcvf data.tar.gz -C/DATA/ AppDataBak/
#解压
tar zxvf data.tar.gz
#查看某文件夹下的所有包括子文件夹文件
ls /DATA/Media -lR | grep "^-" | wc -l
# ls -lR|grep "^d"| wc -l 查看某个文件夹下文件夹的个数,包括子文件夹下的文件夹个数。
#查看固定文件夹大小
du -sh /DATA
}
USB_Start_Auto() {
((EUID)) && sudo_cmd="sudo"
$sudo_cmd systemctl enable devmon@devmon
$sudo_cmd systemctl start devmon@devmon
}
USB_Stop_Auto() {
((EUID)) && sudo_cmd="sudo"
$sudo_cmd systemctl stop devmon@devmon
$sudo_cmd systemctl disable devmon@devmon
$sudo_cmd udevil clean
}
GetDeviceTree(){
cat /proc/device-tree/model
}
# restart samba service
RestartSMBD(){
$sudo_cmd systemctl restart smbd
}
# edit user password $1:username
EditSmabaUserPassword(){
$sudo_cmd smbpasswd $1
}
AddSmabaUser(){
$sudo_cmd useradd $1
$sudo_cmd smbpasswd -a $1 <<EOF
$2
$2
EOF
}
# $1:username $2:host $3:share $4:port $5:mountpoint $6:password
MountCIFS(){
$sudo_cmd mount -t cifs -o username=$1,password=$6,port=$4 //$2/$3 $5
}
# $1:service name
CheckServiceStatus(){
rs="`systemctl status $1 |grep -E 'Active|PID'`"
#echo "$rs"
run="`echo "$rs" |grep -B 2 'running'`"
fai="`echo "$rs" |grep -E -B 2 'failed|inactive|dead'`"
if [ "$run" == "" ]
then
echo "failed"
else
echo "running"
fi
}
UDEVILUmount(){
$sudo_cmd udevil umount -f $1
}

View file

@ -1,268 +0,0 @@
#!/bin/bash
###
# @Author: LinkLeong link@icewhale.com
# @Date: 2022-06-30 10:08:33
# @LastEditors: LinkLeong
# @LastEditTime: 2022-07-01 11:18:07
# @FilePath: /CasaOS/shell/update.sh
# @Description:
###
((EUID)) && sudo_cmd="sudo"
# SYSTEM INFO
readonly UNAME_M="$(uname -m)"
# CasaOS PATHS
readonly CASA_REPO=IceWhaleTech/CasaOS
readonly CASA_UNZIP_TEMP_FOLDER=/tmp/casaos
readonly CASA_BIN=casaos
readonly CASA_BIN_PATH=/usr/bin/casaos
readonly CASA_CONF_PATH=/etc/casaos.conf
readonly CASA_SERVICE_PATH=/etc/systemd/system/casaos.service
readonly CASA_HELPER_PATH=/usr/share/casaos/shell/
readonly CASA_USER_CONF_PATH=/var/lib/casaos/conf/
readonly CASA_DB_PATH=/var/lib/casaos/db/
readonly CASA_TEMP_PATH=/var/lib/casaos/temp/
readonly CASA_LOGS_PATH=/var/log/casaos/
readonly CASA_PACKAGE_EXT=".tar.gz"
readonly CASA_RELEASE_API="https://api.github.com/repos/${CASA_REPO}/releases"
readonly CASA_OPENWRT_DOCS="https://github.com/IceWhaleTech/CasaOS-OpenWrt"
readonly COLOUR_RESET='\e[0m'
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
)
Target_Arch=""
Target_Distro="debian"
Target_OS="linux"
Casa_Tag=""
#######################################
# Custom printing function
# Globals:
# None
# Arguments:
# $1 0:OK 1:FAILED 2:INFO 3:NOTICE
# message
# Returns:
# None
#######################################
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"
}
# 0 Check_exist
Check_Exist() {
#Create Dir
Show 2 "Create Folders."
${sudo_cmd} mkdir -p ${CASA_HELPER_PATH}
${sudo_cmd} mkdir -p ${CASA_LOGS_PATH}
${sudo_cmd} mkdir -p ${CASA_USER_CONF_PATH}
${sudo_cmd} mkdir -p ${CASA_DB_PATH}
${sudo_cmd} mkdir -p ${CASA_TEMP_PATH}
Show 2 "Start cleaning up the old version."
${sudo_cmd} rm -rf /usr/lib/systemd/system/casaos.service
${sudo_cmd} rm -rf /lib/systemd/system/casaos.service
if [[ -f "/casaOS/server/conf/conf.ini" ]]; then
${sudo_cmd} cp -rf /casaOS/server/conf/conf.ini ${CASA_CONF_PATH}
${sudo_cmd} cp -rf /casaOS/server/conf/*.json ${CASA_USER_CONF_PATH}
fi
if [[ -d "/casaOS/server/db" ]]; then
${sudo_cmd} cp -rf /casaOS/server/db/* ${CASA_DB_PATH}
fi
Show 0 "Clearance completed."
}
# 1 Check Arch
Check_Arch() {
case $UNAME_M in
*aarch64*)
Target_Arch="arm64"
;;
*64*)
Target_Arch="amd64"
;;
*armv7*)
Target_Arch="arm-7"
;;
*)
Show 1 "Aborted, unsupported or unknown architecture: $UNAME_M"
exit 1
;;
esac
Show 0 "Your hardware architecture is : $UNAME_M"
}
#Download CasaOS Package
Download_CasaOS() {
Show 2 "Downloading CasaOS for ${Target_OS}/${Target_Arch}..."
Net_Getter="curl -fsSLk"
Casa_Package="${Target_OS}-${Target_Arch}-casaos${CASA_PACKAGE_EXT}"
if [[ ! -n "$version" ]]; then
Casa_Tag="$(${Net_Getter} ${CASA_RELEASE_API}/latest | grep -o '"tag_name": ".*"' | sed 's/"//g' | sed 's/tag_name: //g')"
elif [[ $version == "pre" ]]; then
Casa_Tag="$(${net_getter} ${CASA_RELEASE_API} | grep -o '"tag_name": ".*"' | sed 's/"//g' | sed 's/tag_name: //g' | sed -n '1p')"
else
Casa_Tag="$version"
fi
Casa_Package_URL="https://github.com/${CASA_REPO}/releases/download/${Casa_Tag}/${Casa_Package}"
echo
# Remove Temp File
${sudo_cmd} rm -rf "$PREFIX/tmp/${Casa_Package}"
# Download Package
${Net_Getter} "${Casa_Package_URL}" >"$PREFIX/tmp/${Casa_Package}"
if [[ $? -ne 0 ]]; then
Show 1 "Download failed, Please check if your internet connection is working and retry."
exit 1
else
Show 0 "Download successful!"
fi
#Extract CasaOS Package
Show 2 "Extracting..."
case "${Casa_Package}" in
*.zip) ${sudo_cmd} unzip -o "$PREFIX/tmp/${Casa_Package}" -d "$PREFIX/tmp/" ;;
*.tar.gz) ${sudo_cmd} tar -xzf "$PREFIX/tmp/${Casa_Package}" -C "$PREFIX/tmp/" ;;
esac
#Setting Executable Permissions
${sudo_cmd} chmod +x "$PREFIX${CASA_UNZIP_TEMP_FOLDER}/${CASA_BIN}"
}
#Install Addons
Install_Addons() {
Show 2 "Installing CasaOS Addons"
${sudo_cmd} cp -rf "$PREFIX${CASA_UNZIP_TEMP_FOLDER}/shell/11-usb-mount.rules" "/etc/udev/rules.d/"
${sudo_cmd} cp -rf "$PREFIX${CASA_UNZIP_TEMP_FOLDER}/shell/usb-mount@.service" "/etc/systemd/system/"
sync
}
#Clean Temp Files
Clean_Temp_Files() {
Show 0 "Clean..."
${sudo_cmd} rm -rf "$PREFIX${CASA_UNZIP_TEMP_FOLDER}"
sync
}
#Install CasaOS
Install_CasaOS() {
Show 2 "Installing..."
# Install Bin
${sudo_cmd} mv -f $PREFIX${CASA_UNZIP_TEMP_FOLDER}/${CASA_BIN} ${CASA_BIN_PATH}
# Install Helper
if [[ -d ${CASA_HELPER_PATH} ]]; then
${sudo_cmd} rm -rf ${CASA_HELPER_PATH}*
fi
${sudo_cmd} cp -rf $PREFIX${CASA_UNZIP_TEMP_FOLDER}/shell/* ${CASA_HELPER_PATH}
#Setting Executable Permissions
${sudo_cmd} chmod +x $PREFIX${CASA_HELPER_PATH}*
# Install Conf
if [[ ! -f ${CASA_CONF_PATH} ]]; then
if [[ -f $PREFIX${CASA_UNZIP_TEMP_FOLDER}/conf/conf.ini.sample ]]; then
${sudo_cmd} mv -f $PREFIX${CASA_UNZIP_TEMP_FOLDER}/conf/conf.ini.sample ${CASA_CONF_PATH}
else
${sudo_cmd} mv -f $PREFIX${CASA_UNZIP_TEMP_FOLDER}/conf/conf.conf.sample ${CASA_CONF_PATH}
fi
fi
sync
if [[ ! -x "$(command -v ${CASA_BIN})" ]]; then
Show 1 "Installation failed, please try again."
exit 1
else
Show 0 "CasaOS Successfully installed."
fi
}
#Generate Service File
Generate_Service() {
if [ -f ${CASA_SERVICE_PATH} ]; then
Show 2 "Try stop CasaOS system service."
# Stop before generation
if [[ $(systemctl is-active ${CASA_BIN} &>/dev/null) ]]; then
${sudo_cmd} systemctl stop ${CASA_BIN}
fi
fi
Show 2 "Create system service for CasaOS."
${sudo_cmd} tee ${CASA_SERVICE_PATH} >/dev/null <<EOF
[Unit]
Description=CasaOS Service
StartLimitIntervalSec=0
[Service]
Type=simple
LimitNOFILE=15210
Restart=always
RestartSec=1
User=root
ExecStart=${CASA_BIN_PATH} -c ${CASA_CONF_PATH}
[Install]
WantedBy=multi-user.target
EOF
Show 0 "CasaOS service Successfully created."
}
# Start CasaOS
Start_CasaOS() {
Show 2 "Create a system startup service for CasaOS."
$sudo_cmd systemctl daemon-reload
$sudo_cmd systemctl enable ${CASA_BIN}
}
Check_Arch
# Step 7: Download CasaOS
Check_Exist
Download_CasaOS
# Step 8: Install Addon
Install_Addons
# Step 9: Install CasaOS
Install_CasaOS
# Step 10: Generate_Service
Generate_Service
# Step 11: Start CasaOS
Start_CasaOS
Clean_Temp_Files

View file

@ -1,136 +0,0 @@
#!/bin/bash
# copy to /casaOS/util/shell path
# chmod 755
log="logger -t usb-mount.sh -s "
ACTION=$1
DEVBASE=$2
DEVICE="/dev/${DEVBASE}"
# See if this drive is already mounted, and if so where
MOUNT_POINT=$(lsblk -l -p -o name,mountpoint | grep ${DEVICE} | awk '{print $2}')
do_mount() {
if [ -n "${MOUNT_POINT}" ]; then
${log} "Warning: ${DEVICE} is already mounted at ${MOUNT_POINT}"
exit 1
fi
# Get info for this drive: $ID_FS_LABEL and $ID_FS_TYPE
eval $(blkid -o udev ${DEVICE} | grep -i -e "ID_FS_LABEL" -e "ID_FS_TYPE")
#ID_FS_LABEL=新加卷
#ID_FS_LABEL_ENC=新加卷
#ID_FS_TYPE=ntfs
# Figure out a mount point to use
# LABEL=${ID_FS_LABEL}
LABEL=${DEVBASE}
if grep -q " /DATA/USB_Storage_${LABEL} " /etc/mtab; then
# Already in use, make a unique one
LABEL+="_${DEVBASE}"
fi
DEV_LABEL="${LABEL}"
# Use the device name in case the drive doesn't have label
if [ -z ${DEV_LABEL} ]; then
DEV_LABEL="${DEVBASE}"
fi
MOUNT_POINT="/DATA/USB_Storage_${DEV_LABEL}"
${log} "Mount point: ${MOUNT_POINT}"
mkdir -p ${MOUNT_POINT}
# MOUNT_POINT="/DATA/USB_Storage1"
# arr=("/DATA/USB_Storage1" "/DATA/USB_Storage2" "/DATA/USB_Storage3" "/DATA/USB_Storage4" "/DATA/USB_Storage5" "/DATA/USB_Storage6" "/DATA/USB_Storage7" "/DATA/USB_Storage8" "/DATA/USB_Storage9" "/DATA/USB_Storage10" "/DATA/USB_Storage11" "/DATA/USB_Storage12")
# for folder in ${arr[@]}; do
# #如果文件夹不存在,创建文件夹
# if [ ! -d "$folder" ]; then
# mkdir -p ${folder}
# MOUNT_POINT=$folder
# break
# fi
# done
# ${log} "Mount point: ${MOUNT_POINT}"
# # Global mount options
# OPTS="rw,relatime"
#
# # File system type specific mount options
# if [[ ${ID_FS_TYPE} == "vfat" ]]; then
# OPTS+=",users,gid=100,umask=000,shortname=mixed,utf8=1,flush"
# fi
# if ! mount -o ${OPTS} ${DEVICE} ${MOUNT_POINT}; then
# ${log} "Error mounting ${DEVICE} (status = $?)"
# rmdir "${MOUNT_POINT}"
# exit 1
# else
# # Track the mounted drives
# echo "${MOUNT_POINT}:${DEVBASE}" | cat >>"/var/log/usb-mount.track"
# fi
#
# ${log} "Mounted ${DEVICE} at ${MOUNT_POINT}"
case ${ID_FS_TYPE} in
vfat)
mount -t vfat -o rw,relatime,users,gid=100,umask=000,shortname=mixed,utf8=1,flush ${DEVICE} ${MOUNT_POINT}
;;
ext[2-4])
mount -o noatime ${DEVICE} ${MOUNT_POINT} >/dev/null 2>&1
;;
exfat)
mount -t exfat ${DEVICE} ${MOUNT_POINT} >/dev/null 2>&1
;;
ntfs)
ntfs-3g ${DEVICE} ${MOUNT_POINT}
;;
iso9660)
mount -t iso9660 ${DEVICE} ${MOUNT_POINT}
;;
*)
/bin/rmdir "${MOUNT_POINT}"
exit 0
;;
esac
}
do_umount() {
if [[ -z ${MOUNT_POINT} ]]; then
${log} "Warning: ${DEVICE} is not mounted"
else
#/bin/kill -9 $(lsof ${MOUNT_POINT})
umount -l ${DEVICE}
${log} "Unmounted ${DEVICE} from ${MOUNT_POINT}"
if [ "`ls -A ${MOUNT_POINT}`" = "" ]; then
/bin/rm -fr "${MOUNT_POINT}"
fi
sed -i.bak "\@${MOUNT_POINT}@d" /var/log/usb-mount.track
fi
}
case "${ACTION}" in
add)
do_mount
;;
remove)
do_umount
;;
*)
exit 1
;;
esac

View file

@ -1,8 +0,0 @@
# copy to /etc/systemd/system path
[Unit]
Description=Mount USB Drive on %i
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/casaOS/server/shell/usb-mount.sh add %i
ExecStop=/casaOS/server/shell/usb-mount.sh remove %i

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com * @Author: LinkLeong link@icewhale.com
* @Date: 2022-02-17 18:53:22 * @Date: 2022-02-17 18:53:22
* @LastEditors: LinkLeong * @LastEditors: LinkLeong
* @LastEditTime: 2022-08-25 10:49:46 * @LastEditTime: 2022-09-06 14:27:42
* @FilePath: /CasaOS/types/system.go * @FilePath: /CasaOS/types/system.go
* @Description: * @Description:
* @Website: https://www.casaos.io * @Website: https://www.casaos.io
@ -10,6 +10,6 @@
*/ */
package types package types
const CURRENTVERSION = "0.3.5.1" const CURRENTVERSION = "0.3.6"
const BODY = " " const BODY = " "

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/ui/img/icon/mstile-150x150.png"/>
<TileColor>#da532c</TileColor>
</tile>
</msapplication>
</browserconfig>

View file

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#363636;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:2;}
@media ( prefers-color-scheme: dark ) {
.st0{fill:none;stroke:#FFFFFF;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:2;}
}
</style>
<path class="st0" d="M12,22c5.5,0,10-4.5,10-10S17.5,2,12,2S2,6.5,2,12S6.5,22,12,22z"/>
<path class="st0" d="M12,22c3.9,0,7-3.1,7-7s-3.1-7-7-7s-7,3.1-7,7S8.1,22,12,22z"/>
<path class="st0" d="M12,22c2.2,0,4-1.8,4-4s-1.8-4-4-4s-4,1.8-4,4S9.8,22,12,22z"/>
</svg>

Before

Width:  |  Height:  |  Size: 877 B

View file

@ -1,55 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="64" height="64" version="1.1" viewBox="0 0 16.933 16.933" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="linearGradient1911" x1="25.085" x2="25.085" y1="24.031" y2="26.412" gradientTransform="translate(-35.822,-21.385)" gradientUnits="userSpaceOnUse">
<stop stop-color="#fcbc19" stop-opacity=".99608" offset="0"/>
<stop stop-color="#f4b61f" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient4625" x1=".52918" x2="16.404" y1="5.0665" y2="5.0665" gradientTransform="translate(-17.925)" gradientUnits="userSpaceOnUse">
<stop stop-color="#b78815" offset="0"/>
<stop stop-color="#e2b24b" stop-opacity="0" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient1951" x1="100" x2="133.19" y1="17.453" y2="51.606" gradientTransform="matrix(.26458 0 0 .26458 -38.033 -.13539)" gradientUnits="userSpaceOnUse">
<stop stop-color="#fce798" offset="0"/>
<stop stop-color="#ffc937" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient11110" x1=".52917" x2="16.404" y1="5.3815" y2="5.3815" gradientTransform="translate(-17.925)" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff" offset="0"/>
<stop stop-color="#fff" stop-opacity="0" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient1119" x1="8.4665" x2="8.4665" y1="6.0853" y2="9.4879" gradientUnits="userSpaceOnUse">
<stop stop-color="#fddb7a" offset="0"/>
<stop stop-color="#ffd970" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient1284" x1="8.4665" x2="8.4665" y1="10.26" y2="13.229" gradientUnits="userSpaceOnUse">
<stop stop-color="#ffd96e" offset="0"/>
<stop stop-color="#ffd561" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient1272" x1="-3.9033" x2="-3.9033" y1="7.7839" y2="15.613" gradientTransform="translate(12.362 -2.1249)" gradientUnits="userSpaceOnUse">
<stop stop-color="#c68d00" offset="0"/>
<stop stop-color="#a67100" offset="1"/>
</linearGradient>
</defs>
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
</cc:Work>
</rdf:RDF>
</metadata>
<g transform="translate(17.925 4.2e-5)">
<path d="m-16.728 2.2489c-0.3653 0-0.66145 0.32575-0.66145 0.72759v2.9636c-0.0026 0.02629-0.0072 0.052-0.0072 0.07906v7.9373c0 0.40184 0.29614 0.72759 0.66144 0.72759h14.552c0.36531 0 0.66144-0.32575 0.66144-0.72759v-9.393c0-0.40184-0.29614-0.72759-0.66144-0.72759v5.16e-4h-8.1993l-0.89864-1.1095s-0.36607-0.478-1.0583-0.478h-1.3229z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="url(#linearGradient1911)" image-rendering="auto" shape-rendering="auto" solid-color="#000000" stop-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;font-variation-settings:normal;inline-size:0;isolation:auto;mix-blend-mode:normal;shape-margin:0;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/>
<path d="m-9.5646 3.8364c-0.11312 0.0018-0.30848-0.01542-0.51986 0.09508-0.73647 0.37946-0.77226 0.59366-1.557 0.71415h-4.9608c-0.21986 0-0.41824 0.08855-0.56171 0.23202-0.13937 0.13936-0.22041 0.33333-0.2253 0.54569v0.2775c0.0049-0.21236 0.08593-0.40633 0.2253-0.54569 0.14347-0.14347 0.34185-0.23202 0.56171-0.23202h4.9608c0.78472-0.1205 0.82051-0.33469 1.557-0.71415 0.21138-0.1105 0.40673-0.09328 0.51986-0.09508h7.3828c0.18216 3.65e-4 0.3472 0.08101 0.46663 0.21239 0.1197 0.13167 0.19378 0.31377 0.19378 0.51469v-0.2775c0-0.20092-0.07408-0.38302-0.19378-0.51469-0.11943-0.13137-0.28447-0.21202-0.46663-0.21239h-1.1652zm-7.8247 2.1037c-0.0026 0.02629-0.0067 0.05201-0.0067 0.07906v0.2775c0-0.02705 0.0041-0.05277 0.0067-0.07906z" fill="url(#linearGradient4625)" opacity=".001" stroke-width=".26458"/>
<path d="m-17.396 13.674v0.28215c0 0.20092 0.07357 0.3825 0.19327 0.51417s0.28553 0.21342 0.46818 0.21342h14.552c0.18265 0 0.34796-0.08175 0.46766-0.21342s0.19378-0.31325 0.19378-0.51417v-0.28215c0 0.20092-0.07409 0.3825-0.19378 0.51417-0.1197 0.13167-0.28501 0.21342-0.46766 0.21342h-14.552c-0.18265 0-0.34848-0.08176-0.46818-0.21342s-0.19327-0.31325-0.19327-0.51417z" fill="#e4a729" fill-opacity=".99608" stroke-width=".26458"/>
<path d="m-10.383 4.0979s-0.35919 0.47868-1.1575 0.79218c-0.03271 0.00587-0.06509 0.011575-0.10077 0.017052h-4.9608c-0.21986 0-0.41824 0.088552-0.56171 0.23202-0.13937 0.13936-0.22042 0.33333-0.2253 0.54569v0.51675c-0.0026 0.02629-0.0067 0.05201-0.0067 0.07906v7.3953c0 0.20092 0.07357 0.3825 0.19327 0.51417s0.28553 0.21342 0.46818 0.21342h14.552c0.18265 0 0.34796-0.08175 0.46766-0.21342s0.19378-0.31325 0.19378-0.51417v-8.851c0-0.20092-0.07408-0.38302-0.19378-0.51469-0.11945-0.13137-0.28449-0.21202-0.46665-0.21239h-7.4821z" fill="url(#linearGradient1951)"/>
<path d="m-10.383 4.0979s-0.35919 0.47868-1.1575 0.79218c-0.03271 0.00587-0.06509 0.011575-0.10077 0.017052h-4.9608c-0.21986 0-0.41824 0.088552-0.56171 0.23202-0.13937 0.13936-0.22041 0.33333-0.2253 0.54569v0.38446c0.0049-0.21236 0.08593-0.40633 0.2253-0.54569 0.14347-0.14347 0.34185-0.23202 0.56171-0.23202h4.9608c0.03568-0.00548 0.06806-0.011184 0.10077-0.017052 0.75911-0.26303 1.2883-0.79218 1.2883-0.79218h8.0707c0.18216 3.704e-4 0.34718 0.081016 0.46663 0.21239 0.1197 0.13167 0.19378 0.31377 0.19378 0.51469v-0.38446c0-0.20092-0.07408-0.38302-0.19378-0.51469-0.11945-0.13137-0.28447-0.21202-0.46663-0.21239h-7.4821zm-7.0062 2.1037c-0.0026 0.02629-0.0067 0.05201-0.0067 0.07906v0.38446c0-0.02705 0.0041-0.05277 0.0067-0.07906z" fill="url(#linearGradient11110)" opacity=".3"/>
</g>
<circle cx="8.4665" cy="9.525" r="3.9687" fill="url(#linearGradient1272)" stroke-linecap="round" stroke-linejoin="round" stroke-width=".1726"/>
<g transform="matrix(.77756 0 0 .77756 10.567 2.0159)">
<g transform="matrix(1.0741 0 0 1.0741 -11.796 -.7153)">
<circle cx="8.4665" cy="7.8051" r="1.7198" fill="url(#linearGradient1119)" stroke-linecap="round" stroke-linejoin="round" stroke-width=".34395" style="paint-order:stroke fill markers"/>
<path d="m5.2916 11.064 5.4e-6 -0.14432c0-0.43295 0.43294-0.72158 0.72157-0.72158h4.9067c0.28863 0 0.72158 0.28863 0.72158 0.72158v0.14432c0 1.3096-1.416 2.1647-3.1749 2.1647-1.7589 0-3.1749-0.85514-3.1749-2.1647z" fill="url(#linearGradient1284)" stroke-width=".14049"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.7 KiB

View file

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="64" height="64" version="1.1" viewBox="0 0 16.933 16.933" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<style type="text/css"/>
<linearGradient id="linearGradient1951" x1="100" x2="133.19" y1="17.453" y2="51.606" gradientTransform="matrix(.26458 0 0 .24792 -20.108 .79576)" gradientUnits="userSpaceOnUse">
<stop stop-color="#26abe7" offset="0"/>
<stop stop-color="#0669bc" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient11110" x1=".52917" x2="16.404" y1="5.3815" y2="5.3815" gradientTransform="matrix(1 0 0 .93702 6.5e-7 .92263)" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff" offset="0"/>
<stop stop-color="#fff" stop-opacity="0" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient1911" x1="25.085" x2="25.085" y1="24.031" y2="26.412" gradientTransform="translate(-17.897,-21.369)" gradientUnits="userSpaceOnUse">
<stop stop-color="#0271ca" offset="0"/>
<stop stop-color="#0768ba" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient9169" x1="7.4082" x2="7.4082" y1="4.2333" y2="5.5561" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff" offset="0"/>
<stop stop-color="#e3e4e5" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient23227" x1=".52916" x2="16.404" y1="14.196" y2="14.196" gradientTransform="translate(-18.282 -.015458)" gradientUnits="userSpaceOnUse">
<stop stop-color="#0a5ba8" stop-opacity=".99608" offset="0"/>
<stop stop-color="#104a8c" stop-opacity=".99608" offset="1"/>
</linearGradient>
</defs>
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
</cc:Work>
</rdf:RDF>
</metadata>
<path d="m1.1977 2.2644c-0.3653 0-0.66145 0.32575-0.66145 0.72759v2.9636c-0.0026 0.02629-0.0072 0.052-0.0072 0.07906v7.9373c0 0.40184 0.29614 0.72759 0.66144 0.72759h14.552c0.36531 0 0.66144-0.32575 0.66144-0.72759v-9.393c0-0.40184-0.29614-0.72759-0.66144-0.72759v5.16e-4h-8.1993l-0.89864-1.1095s-0.36607-0.478-1.0583-0.478h-1.3229z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="url(#linearGradient1911)" image-rendering="auto" shape-rendering="auto" solid-color="#000000" stop-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;font-variation-settings:normal;inline-size:0;isolation:auto;mix-blend-mode:normal;shape-margin:0;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/>
<g fill="#5e4aa6" stroke-width=".26458">
<circle cx="-330.35" cy="-328.38" r="0"/>
<circle cx="-312.11" cy="-326.25" r="0"/>
<circle cx="-306.02" cy="-333.07" r="0"/>
<circle cx="-308.84" cy="-326.01" r="0"/>
<circle cx="-328.8" cy="-330.45" r="0"/>
<g transform="translate(24.108 -4.592)">
<circle cx="-330.35" cy="-328.38" r="0"/>
<circle cx="-312.11" cy="-326.25" r="0"/>
<circle cx="-306.02" cy="-333.07" r="0"/>
<circle cx="-308.84" cy="-326.01" r="0"/>
<circle cx="-328.8" cy="-330.45" r="0"/>
</g>
<g transform="translate(2.3479 -14.944)">
<circle cx="-330.35" cy="-328.38" r="0"/>
<circle cx="-312.11" cy="-326.25" r="0"/>
<circle cx="-306.02" cy="-333.07" r="0"/>
<circle cx="-308.84" cy="-326.01" r="0"/>
<circle cx="-328.8" cy="-330.45" r="0"/>
</g>
<g transform="translate(.000295 -.00036978)">
<circle cx="-330.35" cy="-328.38" r="0"/>
<circle cx="-312.11" cy="-326.25" r="0"/>
<circle cx="-306.02" cy="-333.07" r="0"/>
<circle cx="-308.84" cy="-326.01" r="0"/>
<circle cx="-328.8" cy="-330.45" r="0"/>
</g>
</g>
<path d="m0.52916 13.691v0.28215c0 0.20092 0.07357 0.3825 0.19327 0.51417s0.28553 0.21342 0.46818 0.21342h14.552c0.18265 0 0.34796-0.08175 0.46766-0.21342s0.19378-0.31325 0.19378-0.51417v-0.28215c0 0.20092-0.07409 0.3825-0.19378 0.51417-0.1197 0.13167-0.28501 0.21342-0.46766 0.21342h-14.552c-0.18265 0-0.34848-0.08176-0.46818-0.21342s-0.19327-0.31325-0.19327-0.51417z" fill="url(#linearGradient23227)" stroke-width=".26458"/>
<rect x=".79373" y="4.2333" width="15.346" height="8.9957" ry=".79373" fill="url(#linearGradient9169)" stroke-linecap="round" stroke-linejoin="round" stroke-width=".1077"/>
<path d="m7.542 4.7624s-0.35919 0.44853-1.1575 0.74229c-0.03271 0.0055-0.06509 0.010846-0.10077 0.015978h-5.4967c-0.21986 0-0.41824 0.082975-0.56171 0.21741-0.13937 0.13058-0.22042 0.31234-0.2253 0.51133v0.48421c0 0.02369-0.0021296 0.045593 0 0.073482l0.52916 6.9301c0.014339 0.18779 0.07357 0.35841 0.19327 0.48179s0.28553 0.19998 0.46818 0.19998h14.552c0.18265 0 0.34796-0.0766 0.46766-0.19998s0.18179-0.29386 0.19378-0.48179l0.52916-8.2935c0.011991-0.18793-0.07408-0.35889-0.19378-0.48227-0.11945-0.1231-0.28449-0.19866-0.46665-0.19901h-8.0112z" fill="url(#linearGradient1951)"/>
<path d="m7.542 4.7624s-0.35919 0.44853-1.1575 0.74229c-0.03271 0.0055-0.06509 0.010846-0.10077 0.015978h-5.49c-0.21986 0-0.41824 0.082975-0.56171 0.21741-0.13937 0.13058-0.22041 0.31234-0.2253 0.51132l-0.0067094 0.36074c0.0049-0.19899 0.092639-0.38123 0.23201-0.51181 0.14347-0.13443 0.34185-0.21741 0.56171-0.21741h5.49c0.03568-0.00513 0.06806-0.01048 0.10077-0.015978 0.75911-0.24646 1.2883-0.74229 1.2883-0.74229h8.5998c0.18216 3.471e-4 0.34718 0.075914 0.46663 0.19901 0.1197 0.12338 0.19378 0.29401 0.19378 0.48227v-0.36025c0-0.18827-0.07408-0.35889-0.19378-0.48227-0.11945-0.1231-0.28447-0.19866-0.46663-0.19901h-8.0112z" fill="url(#linearGradient11110)" opacity=".3"/>
</svg>

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View file

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><svg width="24" height="24" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M24 44C35.0457 44 44 35.0457 44 24C44 12.9543 35.0457 4 24 4C12.9543 4 4 12.9543 4 24C4 35.0457 12.9543 44 24 44Z" stroke="#333" stroke-width="4" stroke-linejoin="round"/><path d="M24 44C31.732 44 38 37.732 38 30C38 22.268 31.732 16 24 16C16.268 16 10 22.268 10 30C10 37.732 16.268 44 24 44Z" stroke="#333" stroke-width="4" stroke-linejoin="round"/><path d="M24 44C28.4183 44 32 40.4183 32 36C32 31.5817 28.4183 28 24 28C19.5817 28 16 31.5817 16 36C16 40.4183 19.5817 44 24 44Z" fill="none" stroke="#333" stroke-width="4" stroke-linejoin="round"/></svg>

Before

Width:  |  Height:  |  Size: 758 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 693 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6 KiB

View file

@ -1,25 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="200.000000pt" height="200.000000pt" viewBox="0 0 200.000000 200.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.14, written by Peter Selinger 2001-2017
</metadata>
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M875 1894 c-11 -2 -51 -11 -88 -20 -341 -78 -610 -364 -673 -714 -82
-459 197 -902 647 -1030 94 -27 277 -37 378 -21 303 47 575 261 690 540 55
133 66 192 65 361 -1 136 -4 165 -27 235 -36 116 -62 170 -123 261 -123 186
-347 336 -566 379 -42 8 -276 15 -303 9z m250 -168 c11 -2 42 -9 70 -16 131
-30 288 -135 387 -260 160 -201 198 -506 93 -745 l-22 -50 2 80 c3 180 -64
351 -184 476 -209 216 -544 260 -807 105 -201 -117 -326 -347 -319 -587 l2
-74 -19 44 c-63 140 -80 332 -44 476 24 94 87 219 147 292 109 133 290 238
448 259 25 3 47 7 49 9 5 4 173 -3 197 -9z m8 -501 c33 -8 85 -31 116 -50 227
-137 305 -418 183 -651 l-21 -39 -1 35 c-9 251 -245 439 -490 389 -186 -38
-323 -200 -330 -389 l-1 -35 -23 45 c-101 194 -61 429 99 578 130 122 292 162
468 117z m-27 -499 c182 -85 183 -345 1 -438 -53 -27 -161 -26 -215 1 -146 75
-180 267 -69 390 63 69 190 90 283 47z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

View file

@ -1,34 +0,0 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="robots" content="noindex">
<script>
if (document.URL.indexOf("ui") === -1) {
window.location.replace("ui")
}
</script>
<link rel="apple-touch-icon" sizes="180x180" href="/ui/img/icon/apple-touch-icon.png">
<link rel="manifest" href="/ui/site.webmanifest">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="/ui/favicon.svg" type="image/svg+xml">
<title>
CasaOS
</title>
<link href="/ui/css/13.3244968c.css" rel="prefetch"><link href="/ui/css/14.edf73182.css" rel="prefetch"><link href="/ui/css/4.0b84e87b.css" rel="prefetch"><link href="/ui/css/5.b9bdfac7.css" rel="prefetch"><link href="/ui/css/6.c3a0b3d4.css" rel="prefetch"><link href="/ui/css/7.fdbd0ee0.css" rel="prefetch"><link href="/ui/css/8.d53635ba.css" rel="prefetch"><link href="/ui/css/9.b2f820da.css" rel="prefetch"><link href="/ui/js/0.js" rel="prefetch"><link href="/ui/js/1.js" rel="prefetch"><link href="/ui/js/10.js" rel="prefetch"><link href="/ui/js/11.js" rel="prefetch"><link href="/ui/js/12.js" rel="prefetch"><link href="/ui/js/13.js" rel="prefetch"><link href="/ui/js/14.js" rel="prefetch"><link href="/ui/js/15.js" rel="prefetch"><link href="/ui/js/2.js" rel="prefetch"><link href="/ui/js/3.js" rel="prefetch"><link href="/ui/js/4.js" rel="prefetch"><link href="/ui/js/5.js" rel="prefetch"><link href="/ui/js/6.js" rel="prefetch"><link href="/ui/js/7.js" rel="prefetch"><link href="/ui/js/8.js" rel="prefetch"><link href="/ui/js/9.js" rel="prefetch"><link href="/ui/css/app.274cdf77.css" rel="preload" as="style"><link href="/ui/css/vendors~app.a44f2742.css" rel="preload" as="style"><link href="/ui/js/app.js" rel="preload" as="script"><link href="/ui/js/vendors~app.js" rel="preload" as="script"><link href="/ui/css/vendors~app.a44f2742.css" rel="stylesheet"><link href="/ui/css/app.274cdf77.css" rel="stylesheet"></head>
<body>
<noscript>
<strong>We're sorry but CasaOS doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<script type="text/javascript" src="/ui/js/vendors~app.js"></script><script type="text/javascript" src="/ui/js/app.js"></script></body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,5 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[14],{"./node_modules/vue-plyr/dist/vue-plyr.css":
/*!*************************************************!*\
!*** ./node_modules/vue-plyr/dist/vue-plyr.css ***!
\*************************************************/
/*! no static exports found */function(module,exports,__webpack_require__){eval("// extracted by mini-css-extract-plugin\n if(false) { var cssReload; }\n \n\n//# sourceURL=webpack:///./node_modules/vue-plyr/dist/vue-plyr.css?")}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,2 +0,0 @@
User-agent: *
Disallow: /

View file

@ -1,14 +0,0 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/ui/img/icon/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

View file

@ -1,6 +0,0 @@
package web
import "embed"
//go:embed index.html favicon.svg browserconfig.xml site.webmanifest robots.txt img js fonts css
var Static embed.FS