Merge branch 'docs/add-user-activate-cli-command' of https://github.com/beclab/Olares into docs/add-user-activate-cli-command

This commit is contained in:
Meow33 2025-10-29 11:27:39 +08:00
commit 3692f5ed7d
83 changed files with 1171 additions and 522 deletions

View file

@ -59,7 +59,7 @@ jobs:
steps:
- id: generate
run: |
v=1.12.2-$(echo $RANDOM$RANDOM)
v=1.12.3-$(echo $RANDOM$RANDOM)
echo "version=$v" >> "$GITHUB_OUTPUT"
upload-cli:

View file

@ -17,7 +17,7 @@ jobs:
steps:
- id: generate
run: |
v=1.12.2-$(date +"%Y%m%d")
v=1.12.3-$(date +"%Y%m%d")
echo "version=$v" >> "$GITHUB_OUTPUT"
release-id:

View file

@ -44,7 +44,7 @@ Olaresは、あなたが自身のデジタル資産をローカルで容易に
![Olaresのアーキテクチ](https://app.cdn.olares.com/github/olares/olares-architecture.jpg)
各コンポーネントの詳細については、[Olares アーキテクチャ](https://docs.olares.com/manual/concepts/system-architecture.html)(英語版)をご参照ください。
各コンポーネントの詳細については、[Olares アーキテクチャ](https://docs.olares.com/developer/concepts/system-architecture.html)(英語版)をご参照ください。
> 🔍**OlaresとNASの違いは何ですか**
>

View file

@ -303,7 +303,7 @@ spec:
chown -R 1000:1000 /uploadstemp && \
chown -R 1000:1000 /appdata
- name: olares-app-init
image: beclab/system-frontend:v1.5.13
image: beclab/system-frontend:v1.5.15
imagePullPolicy: IfNotPresent
command:
- /bin/sh

View file

@ -10,7 +10,7 @@ function command_exists() {
if [[ x"$VERSION" == x"" ]]; then
if [[ "$LOCAL_RELEASE" == "1" ]]; then
ts=$(date +%Y%m%d%H%M%S)
export VERSION="1.12.2-$ts"
export VERSION="1.12.3-$ts"
echo "will build and use a local release of Olares with version: $VERSION"
echo ""
else
@ -20,7 +20,7 @@ fi
if [[ "x${VERSION}" == "x" || "x${VERSION:3}" == "xVERSION__" ]]; then
echo "error: Olares version is unspecified, please set the VERSION env var and rerun this script."
echo "for example: VERSION=1.12.2-20241124 bash $0"
echo "for example: VERSION=1.12.3-20241124 bash $0"
exit 1
fi

View file

@ -149,7 +149,7 @@ export VERSION="#__VERSION__"
if [[ "x${VERSION}" == "x" || "x${VERSION:3}" == "xVERSION__" ]]; then
echo "error: Olares version is unspecified, please set the VERSION env var and rerun this script."
echo "for example: VERSION=1.12.2-20241124 bash $0"
echo "for example: VERSION=1.12.3-20241124 bash $0"
exit 1
fi

View file

@ -21,6 +21,11 @@ systemEnvs:
type: url
editable: true
required: true
# docker hub mirror endpoint for docker.io registry
- envName: OLARES_SYSTEM_DOCKERHUB_SERVICE
type: url
editable: true
required: false
# the legacy OLARES_ROOT_DIR
- envName: OLARES_SYSTEM_ROOT_PATH
default: /olares

View file

@ -49,7 +49,7 @@ func NewCmdRelease() *cobra.Command {
}
if version == "" {
version = fmt.Sprintf("1.12.2-%s", time.Now().Format("20060102150405"))
version = fmt.Sprintf("1.12.3-%s", time.Now().Format("20060102150405"))
fmt.Printf("--version unspecified, using: %s\n", version)
time.Sleep(1 * time.Second)
}

View file

@ -10,11 +10,12 @@ import (
)
type activateUserOptions struct {
Mnemonic string
BflUrl string
VaultUrl string
Password string
OlaresId string
Mnemonic string
BflUrl string
VaultUrl string
Password string
OlaresId string
ResetPassword string
Location string
Language string
@ -53,6 +54,7 @@ func (o *activateUserOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().BoolVar(&o.EnableTunnel, "enable-tunnel", false, "Enable tunnel mode (default: false)")
cmd.Flags().StringVar(&o.Host, "host", "", "FRP host (only used when tunnel is enabled)")
cmd.Flags().StringVar(&o.Jws, "jws", "", "FRP JWS token (only used when tunnel is enabled)")
cmd.Flags().StringVar(&o.ResetPassword, "reset-password", "", "New password for resetting (required for password reset)")
}
func (o *activateUserOptions) Validate() error {
@ -65,6 +67,9 @@ func (o *activateUserOptions) Validate() error {
if o.Mnemonic == "" {
return fmt.Errorf("Mnemonic is required")
}
if o.ResetPassword == "" {
return fmt.Errorf("Reset password is required")
}
return nil
}
@ -88,7 +93,7 @@ func (c *activateUserOptions) Run() error {
return fmt.Errorf("failed to initialize global stores: %v", err)
}
err = wizard.UserBindTerminus(c.Mnemonic, c.BflUrl, c.VaultUrl, c.Password, c.OlaresId, localName)
accessToken, err := wizard.UserBindTerminus(c.Mnemonic, c.BflUrl, c.VaultUrl, c.Password, c.OlaresId, localName)
if err != nil {
return fmt.Errorf("user bind failed: %v", err)
}
@ -96,7 +101,7 @@ func (c *activateUserOptions) Run() error {
log.Printf("✅ Vault activation completed successfully!")
log.Printf("🚀 Starting system activation wizard...")
wizardConfig := wizard.CustomWizardConfig(c.Location, c.Language, c.EnableTunnel, c.Host, c.Jws, c.Password, c.Password)
wizardConfig := wizard.CustomWizardConfig(c.Location, c.Language, c.EnableTunnel, c.Host, c.Jws, c.Password, c.ResetPassword)
log.Printf("Wizard configuration:")
log.Printf(" Location: %s", wizardConfig.System.Location)
@ -107,7 +112,7 @@ func (c *activateUserOptions) Run() error {
log.Printf(" FRP JWS: %s", wizardConfig.System.FRP.Jws)
}
err = wizard.RunActivationWizard(c.BflUrl, "", wizardConfig)
err = wizard.RunActivationWizard(c.BflUrl, accessToken, wizardConfig)
if err != nil {
return fmt.Errorf("activation wizard failed: %v", err)
}

View file

@ -233,8 +233,20 @@ type InstallNvidiaContainerToolkit struct {
}
func (t *InstallNvidiaContainerToolkit) Execute(runtime connector.Runtime) error {
containerdDropInDir := "/etc/containerd/config.d"
containerdConfigFile := "/etc/containerd/config.toml"
if util.IsExist(containerdDropInDir) {
if err := os.RemoveAll(containerdDropInDir); err != nil {
return errors.Wrap(errors.WithStack(err), "Failed to remove containerd drop-in directory")
}
}
if util.IsExist(containerdConfigFile) {
if _, err := runtime.GetRunner().SudoCmd(fmt.Sprintf("sed -i '/^import/d' %s", containerdConfigFile), false, false); err != nil {
return errors.Wrap(errors.WithStack(err), "Failed to remove import section from containerd config file")
}
}
logger.Debugf("install nvidia-container-toolkit")
if _, err := runtime.GetRunner().SudoCmd("apt-get update && sudo apt-get install -y nvidia-container-toolkit=1.17.9-1 nvidia-container-toolkit-base=1.17.9-1 jq", false, true); err != nil {
if _, err := runtime.GetRunner().SudoCmd("apt-get update && sudo apt-get install -y --allow-downgrades nvidia-container-toolkit=1.17.9-1 nvidia-container-toolkit-base=1.17.9-1 jq", false, true); err != nil {
return errors.Wrap(errors.WithStack(err), "Failed to apt-get install nvidia-container-toolkit")
}
return nil

110
cli/pkg/upgrade/1_12_2.go Normal file
View file

@ -0,0 +1,110 @@
package upgrade
import (
"fmt"
"os/exec"
"strings"
"time"
"github.com/Masterminds/semver/v3"
"github.com/beclab/Olares/cli/pkg/core/task"
"github.com/beclab/Olares/cli/pkg/gpu"
"github.com/beclab/Olares/cli/version"
)
var version_1_12_2 = semver.MustParse("1.12.2")
type upgrader_1_12_2 struct {
breakingUpgraderBase
}
func (u upgrader_1_12_2) Version() *semver.Version {
cliVersion, err := semver.NewVersion(version.VERSION)
// tolerate local dev version
if err != nil {
return version_1_12_2
}
if samePatchLevelVersion(version_1_12_2, cliVersion) && getReleaseLineOfVersion(cliVersion) == mainLine {
return cliVersion
}
return version_1_12_2
}
func (u upgrader_1_12_2) AddedBreakingChange() bool {
if u.Version().Equal(version_1_12_2) {
// if this version introduced breaking change
return true
}
return false
}
func nvidiactkNeedsMigration() (bool, error) {
_, err := exec.LookPath("nvidia-ctk")
if err != nil {
return false, nil
}
out, err := exec.Command("nvidia-ctk", "-v").Output()
if err != nil {
return false, err
}
lines := strings.Split(string(out), "\n")
var version *semver.Version
for _, line := range lines {
var versionStr string
if n, err := fmt.Sscanf(line, "NVIDIA Container Toolkit CLI version %s", &versionStr); n == 1 && err == nil {
versionStr = strings.TrimSpace(versionStr)
version, err = semver.NewVersion(versionStr)
if err != nil {
continue
}
break
}
}
if version == nil {
return false, fmt.Errorf("failed to parse nvidia-ctk version")
}
minVer := semver.MustParse("1.18.0")
if version.GreaterThanEqual(minVer) {
return true, nil
}
return false, nil
}
func (u upgrader_1_12_2) PrepareForUpgrade() []task.Interface {
var preTasks []task.Interface
needsMigration, err := nvidiactkNeedsMigration()
if err != nil || needsMigration {
preTasks = append(preTasks,
&task.LocalTask{
Name: "InstallNvidiaContainerToolkit",
Action: new(gpu.InstallNvidiaContainerToolkit),
Retry: 5,
Delay: 10 * time.Second,
},
&task.LocalTask{
Name: "ConfigureContainerdRuntime",
Action: new(gpu.ConfigureContainerdRuntime),
Retry: 5,
Delay: 10 * time.Second,
},
)
}
preTasks = append(preTasks, u.upgraderBase.PrepareForUpgrade()...)
return preTasks
}
func (u upgrader_1_12_2) UpgradeSystemComponents() []task.Interface {
var preTasks []task.Interface
preTasks = append(preTasks,
&task.LocalTask{
Name: "UpgradeL4",
Action: new(upgradeL4),
Retry: 5,
Delay: 10 * time.Second,
})
return append(preTasks, u.upgraderBase.UpgradeSystemComponents()...)
}
func init() {
registerMainUpgrader(upgrader_1_12_2{})
}

View file

@ -1,8 +1,13 @@
package wizard
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/json"
"fmt"
"log"
@ -21,10 +26,10 @@ type App struct {
func NewApp(sender Sender) *App {
// Create simplified client state (backend CLI doesn't need complex state management)
state := &SimpleClientState{}
// Initialize Client (corresponds to original TypeScript's new Client(this.state, sender, hook))
client := NewClient(state, sender)
return &App{
Version: "3.0",
API: client,
@ -35,7 +40,7 @@ func NewApp(sender Sender) *App {
func NewAppWithBaseURL(baseURL string) *App {
// Create HTTP Sender
sender := NewHTTPSender(baseURL)
// Create App with HTTP Sender
return NewApp(sender)
}
@ -76,7 +81,7 @@ func (s *SimpleClientState) GetDevice() *DeviceInfo {
// Signup function - based on original TypeScript signup method (ref: app.ts)
func (a *App) Signup(params SignupParams) (*CreateAccountResponse, error) {
log.Printf("Starting signup process for DID: %s", params.DID)
// 1. Initialize account object (ref: app.ts line 954-959)
account := &Account{
ID: generateUUID(),
@ -90,27 +95,34 @@ func (a *App) Signup(params SignupParams) (*CreateAccountResponse, error) {
},
Orgs: []OrgInfo{}, // Initialize as empty array to prevent undefined
Settings: AccountSettings{},
Version: "3.0.14",
}
// Initialize account with master password (ref: account.ts line 182-190)
err := a.initializeAccount(account, params.MasterPassword)
if err != nil {
return nil, fmt.Errorf("failed to initialize account: %v", err)
}
log.Printf("Account initialized: ID=%s, DID=%s, Name=%s", account.ID, account.DID, account.Name)
// 2. Initialize auth object (ref: app.ts line 964-970)
auth := NewAuth(params.DID)
authKey, err := auth.GetAuthKey(params.MasterPassword)
if err != nil {
return nil, fmt.Errorf("failed to get auth key: %v", err)
}
// Calculate verifier (ref: app.ts line 968-970)
srpClient := NewSRPClient(SRPGroup4096)
err = srpClient.Initialize(authKey)
if err != nil {
return nil, fmt.Errorf("failed to initialize SRP client: %v", err)
}
auth.Verifier = srpClient.GetV()
log.Printf("SRP verifier generated: %x...", auth.Verifier[:8])
// 3. Send create account request to server (ref: app.ts line 973-987)
createParams := CreateAccountParams{
Account: *account,
@ -121,36 +133,45 @@ func (a *App) Signup(params SignupParams) (*CreateAccountResponse, error) {
BFLUser: params.BFLUser,
JWS: params.JWS,
}
response, err := a.API.CreateAccount(createParams)
if err != nil {
return nil, fmt.Errorf("failed to create account on server: %v", err)
}
log.Printf("Account created on server successfully")
log.Printf("MFA token received: %s", response.MFA)
// 4. Login to newly created account (ref: app.ts line 991)
loginParams := LoginParams{
DID: params.DID,
Password: params.MasterPassword,
}
err = a.Login(loginParams)
if err != nil {
return nil, fmt.Errorf("failed to login after signup: %v", err)
}
log.Printf("Login after signup successful")
// 5. Activate account (ref: app.ts line 1039-1046)
// 5. Initialize main vault and create TOTP item (ref: app.ts line 1003-1038)
// err = a.initializeMainVaultWithTOTP(response.MFA)
// if err != nil {
// log.Printf("Warning: Failed to initialize main vault with TOTP: %v", err)
// // Don't return error as account creation was successful
// } else {
// log.Printf("Main vault initialized with TOTP item successfully")
// }
// 6. Activate account (ref: app.ts line 1039-1046)
activeParams := ActiveAccountParams{
ID: a.API.State.GetAccount().ID, // Use logged-in account ID
BFLToken: params.BFLToken,
BFLUser: params.BFLUser,
JWS: params.JWS,
}
err = a.API.ActiveAccount(activeParams)
if err != nil {
log.Printf("Warning: Failed to activate account: %v", err)
@ -158,7 +179,7 @@ func (a *App) Signup(params SignupParams) (*CreateAccountResponse, error) {
} else {
log.Printf("Account activated successfully")
}
log.Printf("Signup completed successfully for DID: %s", params.DID)
return response, nil
}
@ -166,21 +187,21 @@ func (a *App) Signup(params SignupParams) (*CreateAccountResponse, error) {
// Login function - simplified version
func (a *App) Login(params LoginParams) error {
log.Printf("Starting login process for DID: %s", params.DID)
// 1. Start creating session
startParams := StartCreateSessionParams{
DID: params.DID,
AuthToken: params.AuthToken,
AsAdmin: params.AsAdmin,
}
startResponse, err := a.API.StartCreateSession(startParams)
if err != nil {
return fmt.Errorf("failed to start create session: %v", err)
}
log.Printf("Session creation started for Account ID: %s", startResponse.AccountID)
// 2. Use SRP for authentication
authKey, err := deriveKeyPBKDF2(
[]byte(params.Password),
@ -191,56 +212,60 @@ func (a *App) Login(params LoginParams) error {
if err != nil {
return fmt.Errorf("failed to derive auth key: %v", err)
}
// 3. SRP client negotiation
srpClient := NewSRPClient(SRPGroup4096)
err = srpClient.Initialize(authKey)
if err != nil {
return fmt.Errorf("failed to initialize SRP client: %v", err)
}
err = srpClient.SetB(startResponse.B.Bytes())
if err != nil {
return fmt.Errorf("failed to set B value: %v", err)
}
log.Printf("SRP negotiation completed")
// 4. Complete session creation
completeParams := CompleteCreateSessionParams{
SRPId: startResponse.SRPId,
AccountID: startResponse.AccountID,
A: Base64Bytes(srpClient.GetA()),
M: Base64Bytes(srpClient.GetM1()),
AddTrustedDevice: false, // Don't add trusted device by default
Kind: "oe", // Based on server logs, kind should be "oe"
Version: "4.0.0", // Based on server logs, version should be "4.0.0"
AddTrustedDevice: false, // Don't add trusted device by default
Kind: "oe", // Based on server logs, kind should be "oe"
Version: "4.0.0", // Based on server logs, version should be "4.0.0"
}
session, err := a.API.CompleteCreateSession(completeParams)
if err != nil {
return fmt.Errorf("failed to complete create session: %v", err)
}
// 5. Set session key
sessionKey := srpClient.GetK()
session.Key = sessionKey
a.API.State.SetSession(session)
log.Printf("Session created: %s", session.ID)
log.Printf("Session key length: %d bytes", len(sessionKey))
log.Printf("Session key (hex): %x", sessionKey)
// 6. Temporarily skip GetAccount call due to signature verification issues
// Create a simplified account object for subsequent operations
// account, err := a.API.GetAccount()
// if err != nil {
// return fmt.Errorf("failed to get account: %v", err)
// }
account := &Account{
ID: startResponse.AccountID,
DID: params.DID,
ID: startResponse.AccountID,
DID: params.DID,
Name: params.DID,
}
a.API.State.SetAccount(account)
log.Printf("Login completed successfully for DID: %s (skipped GetAccount due to signature issue)", params.DID)
return nil
}
@ -271,12 +296,12 @@ func (c *Client) CreateAccount(params CreateAccountParams) (*CreateAccountRespon
if err != nil {
return nil, err
}
var result CreateAccountResponse
if err := c.parseResponse(response.Result, &result); err != nil {
return nil, fmt.Errorf("failed to parse CreateAccount response: %v", err)
}
return &result, nil
}
@ -292,17 +317,17 @@ func (c *Client) StartCreateSession(params StartCreateSessionParams) (*StartCrea
if err != nil {
return nil, err
}
// Add debug info: print raw response
if responseBytes, err := json.Marshal(response.Result); err == nil {
log.Printf("StartCreateSession raw response: %s", string(responseBytes))
}
var result StartCreateSessionResponse
if err := c.parseResponse(response.Result, &result); err != nil {
return nil, fmt.Errorf("failed to parse StartCreateSession response: %v", err)
}
return &result, nil
}
@ -312,12 +337,12 @@ func (c *Client) CompleteCreateSession(params CompleteCreateSessionParams) (*Ses
if err != nil {
return nil, err
}
var result Session
if err := c.parseResponse(response.Result, &result); err != nil {
return nil, fmt.Errorf("failed to parse CompleteCreateSession response: %v", err)
}
return &result, nil
}
@ -327,12 +352,27 @@ func (c *Client) GetAccount() (*Account, error) {
if err != nil {
return nil, err
}
var result Account
if err := c.parseResponse(response.Result, &result); err != nil {
return nil, fmt.Errorf("failed to parse GetAccount response: %v", err)
}
return &result, nil
}
func (c *Client) UpdateVault(vault Vault) (*Vault, error) {
requestParams := []interface{}{vault}
response, err := c.call("updateVault", requestParams)
if err != nil {
return nil, err
}
var result Vault
if err := c.parseResponse(response.Result, &result); err != nil {
return nil, fmt.Errorf("failed to parse UpdateVault response: %v", err)
}
return &result, nil
}
@ -359,7 +399,7 @@ type ActiveAccountParams struct {
}
type StartCreateSessionParams struct {
DID string `json:"did"`
DID string `json:"did"`
AuthToken *string `json:"authToken,omitempty"`
AsAdmin *bool `json:"asAdmin,omitempty"`
}
@ -418,7 +458,7 @@ func (a *Auth) GetAuthKey(password string) ([]byte, error) {
if len(a.KeyParams.Salt) == 0 {
a.KeyParams.Salt = Base64Bytes(generateRandomBytes(16))
}
// Use PBKDF2 to derive key (ref: auth.ts line 284 and crypto.ts line 78-101)
return deriveKeyPBKDF2(
[]byte(password),
@ -451,3 +491,236 @@ func generateRandomBytes(length int) []byte {
func getCurrentTimeISO() string {
return time.Now().UTC().Format(time.RFC3339)
}
// initializeMainVaultWithTOTP initializes main vault and creates TOTP item (ref: app.ts line 1003-1038)
func (a *App) initializeMainVaultWithTOTP(mfaToken string) error {
account := a.API.State.GetAccount()
if account == nil {
return fmt.Errorf("account is null")
}
// 1. Initialize main vault (ref: server.ts line 1573-1579)
vault := &Vault{
Kind: "vault", // Serializable.kind getter (ref: vault.ts line 18-20)
ID: generateUUID(),
Name: "My Vault",
Owner: account.ID,
Created: getCurrentTimeISO(),
Updated: getCurrentTimeISO(),
Items: []VaultItem{}, // Initialize empty items array
Version: "4.0.0", // Serialization version (ref: encoding.ts toRaw)
}
// 2. Initialize parent class fields (SharedContainer extends BaseContainer)
// BaseContainer has: encryptionParams: AESEncryptionParams = new AESEncryptionParams()
vault.EncryptionParams = EncryptionParams{
Algorithm: "AES-GCM",
TagSize: 128,
KeySize: 256,
IV: "", // Empty, will be set when data is encrypted
AdditionalData: "", // Empty, will be set when data is encrypted
Version: "4.0.0",
}
// SharedContainer has: keyParams: RSAEncryptionParams = new RSAEncryptionParams()
vault.KeyParams = map[string]any{
"algorithm": "RSA-OAEP",
"hash": "SHA-256",
"kind": "c",
"version": "4.0.0",
}
// SharedContainer has: accessors: Accessor[] = []
vault.Accessors = []map[string]any{} // Empty array, will be populated via updateAccessors()
log.Printf("Main vault initialized: ID=%s, Name=%s, Owner=%s", vault.ID, vault.Name, vault.Owner)
// 2. Get authenticator template (ref: app.ts line 1008-1014)
template := GetAuthenticatorTemplate()
if template == nil {
return fmt.Errorf("authenticator template is null")
}
// 3. Set MFA token value (ref: app.ts line 1015)
template.Fields[0].Value = mfaToken
log.Printf("TOTP template prepared with MFA token: %s...", mfaToken[:min(8, len(mfaToken))])
// 4. Create vault item (ref: app.ts line 1024-1033)
item, err := a.createVaultItem(CreateVaultItemParams{
Name: account.Name,
Vault: vault,
Fields: template.Fields,
Tags: []string{},
Icon: template.Icon,
Type: VaultTypeTerminusTotp,
})
if err != nil {
return fmt.Errorf("failed to create vault item: %v", err)
}
log.Printf("TOTP vault item created: ID=%s, Name=%s", item.ID, item.Name)
log.Printf("TOTP field value: %s", item.Fields[0].Value)
// 5. Add item to vault
vault.Items = append(vault.Items, *item)
// 6. Update vault on server (ref: app.ts line 2138: await this.addItems([item], vault))
// Note: The vault is created empty without encryption. Items will be encrypted when
// the user unlocks the vault for the first time via vault.unlock() -> vault.updateAccessors()
err = a.updateVault(vault)
if err != nil {
return fmt.Errorf("failed to update vault on server: %v", err)
}
log.Printf("Vault updated on server successfully")
return nil
}
// CreateVaultItemParams parameters for creating a vault item
type CreateVaultItemParams struct {
Name string
Vault *Vault
Fields []Field
Tags []string
Icon string
Type VaultType
}
// createVaultItem creates a new vault item (ref: app.ts line 2096-2141)
func (a *App) createVaultItem(params CreateVaultItemParams) (*VaultItem, error) {
account := a.API.State.GetAccount()
if account == nil {
return nil, fmt.Errorf("account is null")
}
// Create vault item (ref: item.ts line 451-475)
item := &VaultItem{
ID: generateUUID(),
Name: params.Name,
Type: params.Type,
Icon: params.Icon,
Fields: params.Fields,
Tags: params.Tags,
Updated: getCurrentTimeISO(),
UpdatedBy: account.ID,
}
log.Printf("Vault item created: ID=%s, Name=%s, Type=%d", item.ID, item.Name, item.Type)
return item, nil
}
// updateVault updates vault on server (ref: app.ts line 1855-2037)
func (a *App) updateVault(vault *Vault) error {
// Update vault revision
vault.Revision = generateUUID()
vault.Updated = getCurrentTimeISO()
// Call server API to update vault
updatedVault, err := a.API.UpdateVault(*vault)
if err != nil {
return fmt.Errorf("failed to update vault on server: %v", err)
}
log.Printf("Vault updated on server: ID=%s, Revision=%s", updatedVault.ID, updatedVault.Revision)
return nil
}
// min returns the minimum of two integers
func min(a, b int) int {
if a < b {
return a
}
return b
}
// initializeAccount initializes account with RSA keys and encryption parameters (ref: account.ts line 182-190)
func (a *App) initializeAccount(account *Account, masterPassword string) error {
// 1. Generate RSA key pair (ref: account.ts line 183-186)
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return fmt.Errorf("failed to generate RSA key pair: %v", err)
}
// 2. Extract public key and encode it (ref: account.ts line 186)
publicKeyDER, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
if err != nil {
return fmt.Errorf("failed to marshal public key: %v", err)
}
account.PublicKey = base64.StdEncoding.EncodeToString(publicKeyDER)
// 3. Set up key derivation parameters (ref: container.ts line 125-133)
salt := generateRandomBytes(16)
account.KeyParams = KeyParams{
Algorithm: "PBKDF2",
Hash: "SHA-256",
KeySize: 256,
Iterations: 100000,
Salt: base64.StdEncoding.EncodeToString(salt),
Version: "3.0.14",
}
// 4. Derive encryption key from master password
encryptionKey := pbkdf2.Key([]byte(masterPassword), salt, account.KeyParams.Iterations, 32, sha256.New)
// 5. Set up encryption parameters (ref: container.ts line 48-56)
iv := generateRandomBytes(16)
additionalData := generateRandomBytes(16)
account.EncryptionParams = EncryptionParams{
Algorithm: "AES-GCM",
TagSize: 128,
KeySize: 256,
IV: base64.StdEncoding.EncodeToString(iv),
AdditionalData: base64.StdEncoding.EncodeToString(additionalData),
Version: "3.0.14",
}
// 6. Create account secrets (private key + signing key)
privateKeyDER := x509.MarshalPKCS1PrivateKey(privateKey)
signingKey := generateRandomBytes(32) // HMAC key
// Combine private key and signing key into account secrets
accountSecrets := struct {
SigningKey []byte `json:"signingKey"`
PrivateKey []byte `json:"privateKey"`
}{
SigningKey: signingKey,
PrivateKey: privateKeyDER,
}
accountSecretsBytes, err := json.Marshal(accountSecrets)
if err != nil {
return fmt.Errorf("failed to marshal account secrets: %v", err)
}
// 7. Encrypt account secrets (ref: container.ts line 59-63)
encryptedData, err := a.encryptAESGCM(encryptionKey, accountSecretsBytes, iv, additionalData)
if err != nil {
return fmt.Errorf("failed to encrypt account secrets: %v", err)
}
account.EncryptedData = base64.StdEncoding.EncodeToString(encryptedData)
log.Printf("Account initialized with RSA key pair and encryption parameters")
log.Printf("Public key length: %d bytes", len(publicKeyDER))
log.Printf("Encrypted data length: %d bytes", len(encryptedData))
return nil
}
// encryptAESGCM encrypts data using AES-GCM
func (a *App) encryptAESGCM(key, plaintext, iv, additionalData []byte) ([]byte, error) {
// Import crypto/aes and crypto/cipher packages are needed at the top of the file
block, err := aes.NewCipher(key)
if err != nil {
return nil, fmt.Errorf("failed to create cipher: %v", err)
}
gcm, err := cipher.NewGCMWithNonceSize(block, 16)
if err != nil {
return nil, fmt.Errorf("failed to create GCM: %v", err)
}
// Encrypt the plaintext using AES-GCM
ciphertext := gcm.Seal(nil, iv, plaintext, additionalData)
return ciphertext, nil
}

View file

@ -24,12 +24,12 @@ type Token struct {
// FirstFactorRequest represents first factor request structure
type FirstFactorRequest struct {
Username string `json:"username"`
Password string `json:"password"`
KeepMeLoggedIn bool `json:"keepMeLoggedIn"`
RequestMethod string `json:"requestMethod"`
TargetURL string `json:"targetURL"`
AcceptCookie bool `json:"acceptCookie"`
Username string `json:"username"`
Password string `json:"password"`
KeepMeLoggedIn bool `json:"keepMeLoggedIn"`
RequestMethod string `json:"requestMethod"`
TargetURL string `json:"targetURL"`
AcceptCookie bool `json:"acceptCookie"`
}
// FirstFactorResponse represents first factor response structure
@ -41,10 +41,10 @@ type FirstFactorResponse struct {
// OnFirstFactor implements first factor authentication (ref: BindTerminusBusiness.ts)
func OnFirstFactor(baseURL, terminusName, osUser, osPwd string, acceptCookie, needTwoFactor bool) (*Token, error) {
log.Printf("Starting onFirstFactor for user: %s", osUser)
// Process password (salted MD5)
processedPassword := passwordAddSort(osPwd)
// Build request
reqData := FirstFactorRequest{
Username: osUser,
@ -54,51 +54,51 @@ func OnFirstFactor(baseURL, terminusName, osUser, osPwd string, acceptCookie, ne
TargetURL: baseURL,
AcceptCookie: acceptCookie,
}
jsonData, err := json.Marshal(reqData)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %v", err)
}
// Send HTTP request
client := &http.Client{
Timeout: 10 * time.Second,
}
reqURL := fmt.Sprintf("%s/api/firstfactor?hideCookie=true", baseURL)
req, err := http.NewRequest("POST", reqURL, strings.NewReader(string(jsonData)))
if err != nil {
return nil, fmt.Errorf("failed to create request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
log.Printf("Sending request to: %s", reqURL)
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %v", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %v", err)
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("HTTP error %d: %s", resp.StatusCode, string(body))
}
var response FirstFactorResponse
if err := json.Unmarshal(body, &response); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
}
if response.Status != "OK" {
return nil, fmt.Errorf("authentication failed: %s", response.Status)
}
log.Printf("First factor authentication successful")
return &response.Data, nil
}
@ -111,7 +111,6 @@ func passwordAddSort(password string) string {
return fmt.Sprintf("%x", hash)
}
// Main authentication function - corresponds to original TypeScript _authenticate function
func Authenticate(req AuthenticateRequest) (*AuthenticateResponse, error) {
if platform == nil {
@ -124,7 +123,7 @@ func Authenticate(req AuthenticateRequest) (*AuthenticateResponse, error) {
// Step 1: If no pending request, start new authentication request
if authReq == nil {
log.Printf("[%s] Step %d: req is empty, starting auth request...", req.Caller, step)
opts := StartAuthRequestOptions{
Type: &req.Type,
Purpose: req.Purpose,
@ -170,49 +169,48 @@ func Authenticate(req AuthenticateRequest) (*AuthenticateResponse, error) {
return res, nil
}
// UserBindTerminus main user binding function (ref: TypeScript version)
func UserBindTerminus(mnemonic, bflUrl, vaultUrl, osPwd, terminusName, localName string) error {
func UserBindTerminus(mnemonic, bflUrl, vaultUrl, osPwd, terminusName, localName string) (string, error) {
log.Printf("Starting userBindTerminus for user: %s", terminusName)
// 1. Initialize global storage
if globalUserStore == nil {
log.Printf("Initializing global stores...")
err := InitializeGlobalStores(mnemonic, terminusName)
if err != nil {
return fmt.Errorf("failed to initialize global stores: %w", err)
return "", fmt.Errorf("failed to initialize global stores: %w", err)
}
log.Printf("Global stores initialized successfully")
}
// 2. Initialize platform and App (if not already initialized)
var app *App
if platform == nil {
log.Printf("Initializing platform...")
// Create App using vaultUrl as base URL
app = NewAppWithBaseURL(vaultUrl)
// Create and set WebPlatform (no need to pass mnemonic, uses global storage)
webPlatform := NewWebPlatform(app.API)
SetPlatform(webPlatform)
log.Printf("Platform initialized successfully with base URL: %s", vaultUrl)
} else {
// If platform already initialized, create new App instance for signup
app = NewAppWithBaseURL(vaultUrl)
}
log.Printf("Using bflUrl: %s", bflUrl)
// 3. Call onFirstFactor to get token (ref: TypeScript implementation)
token, err := OnFirstFactor(bflUrl, terminusName, localName, osPwd, false, false)
if err != nil {
return fmt.Errorf("onFirstFactor failed: %v", err)
return "", fmt.Errorf("onFirstFactor failed: %v", err)
}
log.Printf("First factor authentication successful, session_id: %s", token.SessionID)
// 4. Execute authentication - call _authenticate function from pkg/activate
authRes, err := Authenticate(AuthenticateRequest{
DID: localName,
@ -222,14 +220,14 @@ func UserBindTerminus(mnemonic, bflUrl, vaultUrl, osPwd, terminusName, localName
Caller: "E001",
})
if err != nil {
return fmt.Errorf("authentication failed: %v", err)
return "", fmt.Errorf("authentication failed: %v", err)
}
log.Printf("Authentication successful for DID: %s", authRes.DID)
// 5. Generate JWS - ref: BindTerminusBusiness.ts
log.Printf("Creating JWS for signup...")
// Extract domain (ref: TypeScript implementation)
domain := vaultUrl
if strings.HasPrefix(domain, "http://") {
@ -237,7 +235,7 @@ func UserBindTerminus(mnemonic, bflUrl, vaultUrl, osPwd, terminusName, localName
} else if strings.HasPrefix(domain, "https://") {
domain = domain[8:]
}
// Use globalUserStore to sign JWS (ref: userStore.signJWS in TypeScript)
jws, err := globalUserStore.SignJWS(map[string]any{
"name": terminusName,
@ -246,14 +244,14 @@ func UserBindTerminus(mnemonic, bflUrl, vaultUrl, osPwd, terminusName, localName
"time": fmt.Sprintf("%d", time.Now().UnixMilli()),
})
if err != nil {
return fmt.Errorf("JWS signing failed: %v", err)
return "", fmt.Errorf("JWS signing failed: %v", err)
}
log.Printf("JWS created successfully: %s...", jws[:50])
// 6. Execute signup (call real implementation in app.go)
log.Printf("Executing signup...")
// Build SignupParams (ref: app.signup in BindTerminusBusiness.ts)
signupParams := SignupParams{
DID: authRes.DID,
@ -265,15 +263,15 @@ func UserBindTerminus(mnemonic, bflUrl, vaultUrl, osPwd, terminusName, localName
BFLUser: localName,
JWS: jws,
}
// Call real app.Signup function
signupResponse, err := app.Signup(signupParams)
if err != nil {
return fmt.Errorf("signup failed: %v", err)
return "", fmt.Errorf("signup failed: %v", err)
}
log.Printf("Signup successful! MFA: %s", signupResponse.MFA)
// Save MFA token to UserStore for next stage use
err = globalUserStore.SetMFA(signupResponse.MFA)
if err != nil {
@ -282,8 +280,8 @@ func UserBindTerminus(mnemonic, bflUrl, vaultUrl, osPwd, terminusName, localName
} else {
log.Printf("MFA token saved to UserStore for future use")
}
log.Printf("User bind to Terminus completed successfully!")
return nil
return token.AccessToken, nil
}

View file

@ -83,27 +83,27 @@ type ErrorCode string
const (
ErrorCodeAuthenticationFailed ErrorCode = "email_verification_failed"
ErrorCodeNotFound ErrorCode = "not_found"
ErrorCodeServerError ErrorCode = "server_error"
ErrorCodeNotFound ErrorCode = "not_found"
ErrorCodeServerError ErrorCode = "server_error"
)
// AccountProvisioning represents account provisioning information
type AccountProvisioning struct {
ID string `json:"id"`
DID string `json:"did"`
Name *string `json:"name,omitempty"`
AccountID *string `json:"accountId,omitempty"`
Status string `json:"status"`
StatusLabel string `json:"statusLabel"`
StatusMessage string `json:"statusMessage"`
ActionURL *string `json:"actionUrl,omitempty"`
ActionLabel *string `json:"actionLabel,omitempty"`
MetaData map[string]any `json:"metaData,omitempty"`
SkipTos bool `json:"skipTos"`
BillingPage any `json:"billingPage,omitempty"`
Quota map[string]any `json:"quota"`
Features map[string]any `json:"features"`
Orgs []string `json:"orgs"`
ID string `json:"id"`
DID string `json:"did"`
Name *string `json:"name,omitempty"`
AccountID *string `json:"accountId,omitempty"`
Status string `json:"status"`
StatusLabel string `json:"statusLabel"`
StatusMessage string `json:"statusMessage"`
ActionURL *string `json:"actionUrl,omitempty"`
ActionLabel *string `json:"actionLabel,omitempty"`
MetaData map[string]any `json:"metaData,omitempty"`
SkipTos bool `json:"skipTos"`
BillingPage any `json:"billingPage,omitempty"`
Quota map[string]any `json:"quota"`
Features map[string]any `json:"features"`
Orgs []string `json:"orgs"`
}
type StartAuthRequestResponse struct {
@ -130,11 +130,11 @@ type AuthenticateRequest struct {
}
type AuthenticateResponse struct {
DID string `json:"did"`
Token string `json:"token"`
AccountStatus AccountStatus `json:"accountStatus"`
Provisioning AccountProvisioning `json:"provisioning"`
DeviceTrusted bool `json:"deviceTrusted"`
DID string `json:"did"`
Token string `json:"token"`
AccountStatus AccountStatus `json:"accountStatus"`
Provisioning AccountProvisioning `json:"provisioning"`
DeviceTrusted bool `json:"deviceTrusted"`
}
type StartAuthRequestOptions struct {
@ -161,9 +161,9 @@ type CompleteAuthRequestParams struct {
}
type CompleteAuthRequestResponse struct {
AccountStatus AccountStatus `json:"accountStatus"`
DeviceTrusted bool `json:"deviceTrusted"`
Provisioning AccountProvisioning `json:"provisioning"`
AccountStatus AccountStatus `json:"accountStatus"`
DeviceTrusted bool `json:"deviceTrusted"`
Provisioning AccountProvisioning `json:"provisioning"`
}
// Session represents a user session
@ -192,19 +192,43 @@ type AccountSettings struct {
// Simplified version, can be extended as needed
}
// EncryptionParams represents AES encryption parameters
type EncryptionParams struct {
Algorithm string `json:"algorithm"` // "AES-GCM"
TagSize int `json:"tagSize"` // 128
KeySize int `json:"keySize"` // 256
IV string `json:"iv"` // Base64 encoded initialization vector
AdditionalData string `json:"additionalData"` // Base64 encoded additional data
Version string `json:"version"` // "3.0.14"
}
// KeyParams represents PBKDF2 key derivation parameters
type KeyParams struct {
Algorithm string `json:"algorithm"` // "PBKDF2"
Hash string `json:"hash"` // "SHA-256"
KeySize int `json:"keySize"` // 256
Iterations int `json:"iterations"` // 100000
Salt string `json:"salt"` // Base64 encoded salt
Version string `json:"version"` // "3.0.14"
}
type Account struct {
ID string `json:"id"`
DID string `json:"did"`
Name string `json:"name"`
Local bool `json:"local,omitempty"`
Created string `json:"created,omitempty"` // ISO 8601 format
Updated string `json:"updated,omitempty"` // ISO 8601 format
PublicKey []byte `json:"publicKey,omitempty"` // RSA public key
MainVault MainVault `json:"mainVault"` // Main vault information
Orgs []OrgInfo `json:"orgs"` // Organization list (important: prevent undefined)
Revision string `json:"revision,omitempty"` // Version control
Kid string `json:"kid,omitempty"` // Key ID
Settings AccountSettings `json:"settings,omitempty"` // Account settings
ID string `json:"id"`
DID string `json:"did"`
Name string `json:"name"`
Local bool `json:"local,omitempty"`
Created string `json:"created,omitempty"` // ISO 8601 format
Updated string `json:"updated,omitempty"` // ISO 8601 format
PublicKey string `json:"publicKey,omitempty"` // Base64 encoded RSA public key
EncryptedData string `json:"encryptedData,omitempty"` // Base64 encoded encrypted data
EncryptionParams EncryptionParams `json:"encryptionParams,omitempty"` // AES encryption parameters
KeyParams KeyParams `json:"keyParams,omitempty"` // PBKDF2 key derivation parameters
MainVault MainVault `json:"mainVault"` // Main vault information
Orgs []OrgInfo `json:"orgs"` // Organization list (important: prevent undefined)
Revision string `json:"revision,omitempty"` // Version control
Kid string `json:"kid,omitempty"` // Key ID
Settings AccountSettings `json:"settings,omitempty"` // Account settings
Version string `json:"version,omitempty"` // Version
}
type DeviceInfo struct {
@ -215,10 +239,10 @@ type DeviceInfo struct {
// Request represents an RPC request
type Request struct {
Method string `json:"method"`
Params []interface{} `json:"params,omitempty"`
Device *DeviceInfo `json:"device,omitempty"`
Auth *RequestAuth `json:"auth,omitempty"`
Method string `json:"method"`
Params []interface{} `json:"params,omitempty"`
Device *DeviceInfo `json:"device,omitempty"`
Auth *RequestAuth `json:"auth,omitempty"`
}
type Response struct {
@ -247,12 +271,12 @@ func (t *ISOTime) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &str); err != nil {
return err
}
parsed, err := time.Parse("2006-01-02T15:04:05.000Z", str)
if err != nil {
return err
}
*t = ISOTime(parsed)
return nil
}
@ -282,7 +306,7 @@ func (b *Base64Bytes) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &str); err != nil {
return err
}
// Server uses URL-safe base64 encoding by default (ref: encoding.ts line 366: urlSafe = true)
// Try base64url decoding first
decoded, err := base64.URLEncoding.DecodeString(str)
@ -297,7 +321,7 @@ func (b *Base64Bytes) UnmarshalJSON(data []byte) error {
}
}
}
*b = Base64Bytes(decoded)
return nil
}
@ -313,5 +337,100 @@ func (b Base64Bytes) Bytes() []byte {
return []byte(b)
}
// ============================================================================
// Vault and VaultItem Structures
// ============================================================================
// VaultType represents the type of vault item
type VaultType int
const (
VaultTypeDefault VaultType = 0
VaultTypeLogin VaultType = 1
VaultTypeCard VaultType = 2
VaultTypeTerminusTotp VaultType = 3
VaultTypeOlaresSSHPassword VaultType = 4
)
// FieldType represents the type of field in a vault item
type FieldType string
const (
FieldTypeUsername FieldType = "username"
FieldTypePassword FieldType = "password"
FieldTypeApiSecret FieldType = "apiSecret"
FieldTypeMnemonic FieldType = "mnemonic"
FieldTypeUrl FieldType = "url"
FieldTypeEmail FieldType = "email"
FieldTypeDate FieldType = "date"
FieldTypeMonth FieldType = "month"
FieldTypeCredit FieldType = "credit"
FieldTypePhone FieldType = "phone"
FieldTypePin FieldType = "pin"
FieldTypeTotp FieldType = "totp"
FieldTypeNote FieldType = "note"
FieldTypeText FieldType = "text"
)
// Field represents a field in a vault item
type Field struct {
Name string `json:"name"`
Type FieldType `json:"type"`
Value string `json:"value"`
}
// VaultItem represents an item in a vault
type VaultItem struct {
ID string `json:"id"`
Name string `json:"name"`
Type VaultType `json:"type"`
Icon string `json:"icon,omitempty"`
Fields []Field `json:"fields"`
Tags []string `json:"tags"`
Updated string `json:"updated"` // ISO 8601 format
UpdatedBy string `json:"updatedBy"`
}
// Vault represents a vault containing items
type Vault struct {
Kind string `json:"kind"` // Always "vault" for Vault objects
ID string `json:"id"`
Name string `json:"name"`
Owner string `json:"owner"`
Created string `json:"created"` // ISO 8601 format
Updated string `json:"updated"` // ISO 8601 format
Revision string `json:"revision,omitempty"`
Items []VaultItem `json:"items,omitempty"`
KeyParams interface{} `json:"keyParams,omitempty"`
EncryptionParams interface{} `json:"encryptionParams,omitempty"`
Accessors interface{} `json:"accessors,omitempty"`
EncryptedData interface{} `json:"encryptedData,omitempty"`
Version string `json:"version,omitempty"` // Serialization version
}
// ItemTemplate represents a template for creating vault items
type ItemTemplate struct {
ID string `json:"id"`
Name string `json:"name"`
Icon string `json:"icon"`
Fields []Field `json:"fields"`
}
// GetAuthenticatorTemplate returns the authenticator template for TOTP items
func GetAuthenticatorTemplate() *ItemTemplate {
return &ItemTemplate{
ID: "authenticator",
Name: "Authenticator",
Icon: "authenticator",
Fields: []Field{
{
Name: "One-Time Password",
Type: FieldTypeTotp,
Value: "", // Will be set with MFA token
},
},
}
}
// JWS-related data structures removed, using Web5 library's jwt.Sign() method directly
// UserItem and JWSSignatureInput removed as they were not actually used

View file

@ -189,25 +189,14 @@ func (u *UserStore) SignJWS(payload map[string]any) (string, error) {
const TerminusDefaultDomain = "olares.cn"
func (u *UserStore) GetTerminusURL() string {
array := strings.Split(u.terminusName, "@")
localURL := u.getLocalURL()
if len(array) == 2 {
return fmt.Sprintf("https://%s%s.%s", localURL, array[0], array[1])
} else {
return fmt.Sprintf("https://%s%s.%s", localURL, array[0], TerminusDefaultDomain)
}
}
func (u *UserStore) GetAuthURL() string {
array := strings.Split(u.terminusName, "@")
localURL := u.getLocalURL()
if len(array) == 2 {
return fmt.Sprintf("https://auth.%s%s.%s/", localURL, array[0], array[1])
return fmt.Sprintf("https://auth.%s%s.%s", localURL, array[0], array[1])
} else {
return fmt.Sprintf("https://auth.%s%s.%s/", localURL, array[0], TerminusDefaultDomain)
return fmt.Sprintf("https://auth.%s%s.%s", localURL, array[0], TerminusDefaultDomain)
}
}

View file

@ -107,12 +107,18 @@ func (w *ActivationWizard) RunWizard() error {
case "wait_reset_password":
log.Println("🔐 Resetting password...")
// Directly perform password reset, no need for complex DNS waiting logic
if err := w.performPasswordReset(); err != nil {
return fmt.Errorf("password reset failed: %v", err)
status, err := w.authRequestTerminusInfo()
if err != nil {
log.Printf("failed to get terminus info by authurl: %v retry ...\n", err)
} else {
if status == "wait_reset_password" {
// Directly perform password reset, no need for complex DNS waiting logic
if err := w.performPasswordReset(); err != nil {
return fmt.Errorf("password reset failed: %v", err)
}
log.Println("✅ Password reset completed")
}
}
log.Println("✅ Password reset completed")
default:
log.Printf("⏳ Unknown status: %s, waiting...", status)
@ -196,15 +202,11 @@ func (w *ActivationWizard) updateTerminusInfo() (string, error) {
// authRequestTerminusInfo backup Terminus information request
func (w *ActivationWizard) authRequestTerminusInfo() (string, error) {
// Use globalUserStore to generate correct terminus_url
var terminusURL string
if globalUserStore != nil {
terminusURL = globalUserStore.GetTerminusURL()
} else {
terminusURL = w.BaseURL
}
var terminusURL = globalUserStore.GetAuthURL()
// Build backup URL (usually terminus_url + '/api/olares-info')
url := fmt.Sprintf("%s/api/olares-info?t=%d", terminusURL, time.Now().UnixMilli())
url := fmt.Sprintf("%s/bfl/info/v1/olares-info?t=%d", terminusURL, time.Now().UnixMilli())
client := &http.Client{
Timeout: 5 * time.Second,
@ -232,12 +234,15 @@ func (w *ActivationWizard) authRequestTerminusInfo() (string, error) {
return "", fmt.Errorf("HTTP error %d: %s", resp.StatusCode, string(body))
}
var terminusInfo TerminusInfo
if err := json.Unmarshal(body, &terminusInfo); err != nil {
var response struct {
Data TerminusInfo `json:"data"`
}
if err := json.Unmarshal(body, &response); err != nil {
return "", fmt.Errorf("failed to parse response: %v", err)
}
return terminusInfo.WizardStatus, nil
return response.Data.WizardStatus, nil
}
// performPasswordReset performs password reset - simplified version

View file

@ -8,11 +8,11 @@ import (
"github.com/beclab/Olares/daemon/internel/watcher"
"github.com/beclab/Olares/daemon/pkg/cluster/state"
"github.com/beclab/Olares/daemon/pkg/commands"
"github.com/beclab/Olares/daemon/pkg/containerd"
"github.com/beclab/Olares/daemon/pkg/utils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/dynamic"
"k8s.io/klog/v2"
)
@ -52,12 +52,6 @@ func (w *systemEnvWatcher) Watch(ctx context.Context) {
return
}
dc, err := utils.GetDynamicClient()
if err != nil {
klog.V(4).Infof("systemenv watcher: dynamic client not ready: %v", err)
return
}
execCtx, cancel := context.WithCancel(ctx)
w.cancel = cancel
w.running = true
@ -69,7 +63,7 @@ func (w *systemEnvWatcher) Watch(ctx context.Context) {
klog.V(4).Info("systemenv watcher exited")
}()
startSystemEnvWatch(execCtx, dc, func(eventType watch.EventType, obj map[string]any) {
startSystemEnvWatch(execCtx, func(eventType watch.EventType, obj map[string]any) {
klog.V(5).Infof("systemenv event: %s", eventType)
if eventType != watch.Added && eventType != watch.Modified {
@ -77,7 +71,7 @@ func (w *systemEnvWatcher) Watch(ctx context.Context) {
}
envName, _ := obj["envName"].(string)
if envName != "OLARES_SYSTEM_CDN_SERVICE" && envName != "OLARES_SYSTEM_REMOTE_SERVICE" {
if envName != "OLARES_SYSTEM_CDN_SERVICE" && envName != "OLARES_SYSTEM_REMOTE_SERVICE" && envName != "OLARES_SYSTEM_DOCKERHUB_SERVICE" {
return
}
@ -104,6 +98,19 @@ func (w *systemEnvWatcher) Watch(ctx context.Context) {
commands.OLARES_REMOTE_SERVICE = val
klog.Infof("updated OLARES_REMOTE_SERVICE: %s -> %s", old, val)
}
case "OLARES_SYSTEM_DOCKERHUB_SERVICE":
if val != "" {
go func(endpoint string) {
if updated, err := containerd.EnsureRegistryMirror(execCtx, containerd.DefaultRegistryName, endpoint); err != nil {
klog.Errorf("failed to ensure docker.io mirror endpoint %s: %v", endpoint, err)
return
} else if updated {
klog.Infof("ensured docker.io mirror endpoint: %s", endpoint)
} else {
klog.V(5).Infof("docker.io mirror endpoint already present: %s", endpoint)
}
}(val)
}
}
})
}()
@ -115,9 +122,14 @@ var systemEnvGVR = schema.GroupVersionResource{
Resource: "systemenvs",
}
func startSystemEnvWatch(ctx context.Context, dc dynamic.Interface, handle func(watch.EventType, map[string]any)) {
func startSystemEnvWatch(ctx context.Context, handle func(watch.EventType, map[string]any)) {
for {
// 1) List existing resources to establish initial state
dc, err := utils.GetDynamicClient()
if err != nil {
klog.V(4).Infof("systemenv watcher: dynamic client not ready: %v", err)
return
}
list, err := dc.Resource(systemEnvGVR).List(ctx, metav1.ListOptions{})
if err != nil {
select {

View file

@ -1,7 +1,9 @@
package containerd
import (
"context"
"fmt"
"net/url"
"strings"
"github.com/containerd/containerd/reference"
@ -48,6 +50,60 @@ func GetRegistryMirror(ctx *fiber.Ctx) (*Mirror, error) {
return &mirror, nil
}
// EnsureRegistryMirror ensures the given endpoint exists for a registry mirror.
// Returns updated=true if a change was made and persisted (containerd restarted),
// or updated=false if the endpoint already existed. Returns error on failure.
func EnsureRegistryMirror(ctx context.Context, registry string, endpoint string) (bool, error) {
if registry == "" {
registry = DefaultRegistryName
}
endpoint = strings.TrimSpace(endpoint)
if endpoint == "" {
return false, fmt.Errorf("endpoint is required")
}
u, err := url.ParseRequestURI(endpoint)
if err != nil || u == nil || u.Host == "" || (u.Scheme != "http" && u.Scheme != "https") {
return false, fmt.Errorf("invalid mirror endpoint: %s", endpoint)
}
endpoint = u.String()
config, err := getConfig()
if err != nil {
return false, err
}
criPluginConfig, err := getCRIPluginConfig(config)
if err != nil {
return false, err
}
if criPluginConfig.Registry.Mirrors == nil {
criPluginConfig.Registry.Mirrors = make(map[string]Mirror)
}
mirror := criPluginConfig.Registry.Mirrors[registry]
exists := false
for _, ep := range mirror.Endpoints {
if ep == endpoint {
exists = true
break
}
}
if !exists {
mirror.Endpoints = append(mirror.Endpoints, endpoint)
criPluginConfig.Registry.Mirrors[registry] = mirror
if err := updateCRIPluginConfig(config, criPluginConfig); err != nil {
return false, err
}
if err := restartContainerd(ctx); err != nil {
klog.Errorf("failed to restart containerd: %v", err)
return false, err
}
return true, nil
}
return false, nil
}
func UpdateRegistryMirror(ctx *fiber.Ctx) (*Mirror, error) {
registry := ctx.Params(ParamRegistryName)
if registry == "" {

View file

@ -67,6 +67,22 @@ func deviceForPath(path string) (string, error) {
// Given a device path (e.g. /dev/sda1), find the top-level block device name (e.g. sda)
func topBlockDeviceName(devPath string) (string, error) {
name := filepath.Base(devPath) // e.g. sda1, nvme0n1p1, dm-0, mapper/xxx -> basename
// Handle LVM devices specially - they may not exist in /sys/class/block
if strings.HasPrefix(devPath, "/dev/mapper/") {
// For LVM devices, try to find the underlying physical device
// Check if it's a symlink to a dm-* device
if realPath, err := filepath.EvalSymlinks(devPath); err == nil {
if strings.HasPrefix(realPath, "/dev/dm-") {
// Use the dm-* device name directly
return filepath.Base(realPath), nil
}
}
// If we can't resolve the LVM device, return the original name
// This will cause diskSizeBySysfs to fail gracefully
return name, nil
}
sysPath := filepath.Join("/sys/class/block", name)
real, err := filepath.EvalSymlinks(sysPath)
if err != nil {
@ -85,6 +101,13 @@ func topBlockDeviceName(devPath string) (string, error) {
// Read /sys/class/block/<dev>/size (in sectors), multiply by 512 to get bytes
func diskSizeBySysfs(topDev string) (uint64, error) {
sizePath := filepath.Join("/sys/class/block", topDev, "size")
// Check if the device exists before trying to read it
if _, err := os.Stat(filepath.Join("/sys/class/block", topDev)); err != nil {
klog.V(4).Infof("Block device %s not found in /sys/class/block, skipping size calculation", topDev)
return 0, fmt.Errorf("block device %s not accessible: %w", topDev, err)
}
b, err := ioutil.ReadFile(sizePath)
if err != nil {
return 0, err
@ -114,7 +137,19 @@ func GetDiskTotalBytesForPath(path string) (uint64, error) {
}
size, err := diskSizeBySysfs(topDev)
if err != nil {
return 0, err
// If sysfs method fails (e.g., for LVM devices), try alternative method
klog.V(4).Infof("Failed to get disk size via sysfs for %s, trying alternative method: %v", topDev, err)
// Try using statfs as fallback for the mount point
fs := syscall.Statfs_t{}
if statErr := syscall.Statfs(abs, &fs); statErr == nil {
total := fs.Blocks * uint64(fs.Bsize)
klog.V(4).Infof("Using statfs fallback for %s: %d bytes", abs, total)
return total, nil
}
// If both methods fail, return the original error
return 0, fmt.Errorf("failed to get disk size for device %s: %w", device, err)
}
return size, nil
}

View file

@ -361,49 +361,6 @@ const side = {
},
],
},
{
text: "Concepts",
collapsed: true,
link: "/manual/concepts/",
items: [
{ text: "Olares architecture", link: "/manual/concepts/system-architecture" },
{ text: "Olares ID",
link: "/manual/concepts/olares-id",
collapsed: true,
items: [
{
text: "Decentralized ID",
link: "/manual/concepts/did",
},
{
text: "Blockchain Registry",
link: "/manual/concepts/registry",
},
{
text: "Verifiable Credential",
link: "/manual/concepts/vc",
},
{
text: "Autonomous Reputation",
link: "/manual/concepts/reputation",
},
// {
// text: "Self-Sovereign Network",
// link: "/manual/concepts/self-sovereign-network",
// },
{
text: "Identity Wallet",
link: "/manual/concepts/wallet",
},
],
},
{ text: "Account", link: "/manual/concepts/account" },
{ text: "Application", link: "/manual/concepts/application" },
{ text: "Network", link: "/manual/concepts/network" },
{ text: "Data", link: "/manual/concepts/data" },
{ text: "Secrets", link: "/manual/concepts/secrets" },
],
},
{ text: "Glossary", link: "/manual/glossary" },
],
"/space/": [
@ -508,7 +465,49 @@ const side = {
],
"/developer/": [
{
text: "Installation deep-dives",
text: "Concepts",
link: "/developer/concepts/",
items: [
{ text: "Olares architecture", link: "/developer/concepts/system-architecture" },
{ text: "Olares ID",
link: "/developer/concepts/olares-id",
collapsed: true,
items: [
{
text: "Decentralized ID",
link: "/developer/concepts/did",
},
{
text: "Blockchain Registry",
link: "/developer/concepts/registry",
},
{
text: "Verifiable Credential",
link: "/developer/concepts/vc",
},
{
text: "Autonomous Reputation",
link: "/developer/concepts/reputation",
},
// {
// text: "Self-Sovereign Network",
// link: "/developer/concepts/self-sovereign-network",
// },
{
text: "Identity Wallet",
link: "/developer/concepts/wallet",
},
],
},
{ text: "Account", link: "/developer/concepts/account" },
{ text: "Application", link: "/developer/concepts/application" },
{ text: "Network", link: "/developer/concepts/network" },
{ text: "Data", link: "/developer/concepts/data" },
{ text: "Secrets", link: "/developer/concepts/secrets" },
],
},
{
text: "Installation deep-dive",
link: "/developer/install/",
items: [
{
@ -831,7 +830,7 @@ export const en = defineConfig({
{ text: "Olares", link: "/manual/overview" },
{ text: "Olares Space", link: "/space/" },
{ text: "Use Cases", link: "/use-cases/" },
{ text: "Developer Guide", link: "/developer/install/" },
{ text: "Developer Guide", link: "/developer/concepts/" },
],
sidebar: side,

View file

@ -363,50 +363,7 @@ const side = {
},
],
},
{
text: "概念",
collapsed: true,
link: "/zh/manual/concepts/",
items: [
{ text: "系统架构", link: "/zh/manual/concepts/system-architecture" },
{ text: "Olares ID",
link: "/zh/manual/concepts/olares-id",
collapsed: true,
items: [
{
text: "去中心化标识符",
link: "/zh/manual//concepts/did",
},
{
text: "DID Registry",
link: "/zh/manual//concepts/registry",
},
{
text: "可验证凭证",
link: "/zh/manual//concepts/vc",
},
{
text: "自治声誉",
link: "/zh/manual//concepts/reputation",
},
// {
// text: "主权网络",
// link: "/zh/manual//concepts/self-sovereign-network",
// },
{
text: "身份钱包",
link: "/zh/manual/concepts/wallet",
},
],
},
{ text: "账户", link: "/zh/manual/concepts/account" },
{ text: "应用", link: "/zh/manual/concepts/application" },
{ text: "网络", link: "/zh/manual/concepts/network" },
{ text: "数据", link: "/zh/manual/concepts/data" },
{ text: "密钥", link: "/zh/manual/concepts/secrets" },
],
},
{ text: "术语", link: "/zh/manual/glossary" },
],
"/zh/space/": [
@ -511,39 +468,81 @@ const side = {
},
],
"/zh/developer/": [
{
text: "Olares 安装详解",
link: "/zh/developer/install/",
items: [
{
text: "安装概述",
link: "/zh/developer/install/installation-overview",
},
{
text: "安装流程",
link: "/zh/developer/install/installation-process",
},
{
text: "Olares Home",
link: "/zh/developer/install/olares-home",
},
{
text: "环境变量",
link: "/zh/developer/install/environment-variables",
},
{
text: "Olares CLI",
collapsed: true,
link: "/zh/developer/install/cli/olares-cli",
items: [
{ text: "gpu", link: "/zh/developer/install/cli/gpu" },
{ text: "osinfo", link: "/zh/developer/install/cli/osinfo" },
{ text: "node", link: "/zh/developer/install/cli/node" },
{
text: "backups",
link: "/zh/developer/install/cli/backups",
collapsed: true,
items: [
{
text: "概念",
link: "/zh/developer/concepts/",
items: [
{ text: "系统架构", link: "/zh/developer/concepts/system-architecture" },
{ text: "Olares ID",
link: "/zh/developer/concepts/olares-id",
collapsed: true,
items: [
{
text: "去中心化标识符",
link: "/zh/developer/concepts/did",
},
{
text: "DID Registry",
link: "/zh/developer/concepts/registry",
},
{
text: "可验证凭证",
link: "/zh/developer/concepts/vc",
},
{
text: "自治声誉",
link: "/zh/developer/concepts/reputation",
},
// {
// text: "主权网络",
// link: "/zh/developer/concepts/self-sovereign-network",
// },
{
text: "身份钱包",
link: "/zh/developer/concepts/wallet",
},
],
},
{ text: "账户", link: "/zh/developer/concepts/account" },
{ text: "应用", link: "/zh/developer/concepts/application" },
{ text: "网络", link: "/zh/developer/concepts/network" },
{ text: "数据", link: "/zh/developer/concepts/data" },
{ text: "密钥", link: "/zh/developer/concepts/secrets" },
],
},
{
text: "Olares 安装详解",
link: "/zh/developer/install/",
items: [
{
text: "安装概述",
link: "/zh/developer/install/installation-overview",
},
{
text: "安装流程",
link: "/zh/developer/install/installation-process",
},
{
text: "Olares Home",
link: "/zh/developer/install/olares-home",
},
{
text: "环境变量",
link: "/zh/developer/install/environment-variables",
},
{
text: "Olares CLI",
collapsed: true,
link: "/zh/developer/install/cli/olares-cli",
items: [
{text: "gpu", link: "/zh/developer/install/cli/gpu"},
{text: "osinfo", link: "/zh/developer/install/cli/osinfo"},
{text: "node", link: "/zh/developer/install/cli/node"},
{
text: "backups",
link: "/zh/developer/install/cli/backups",
collapsed: true,
items: [
{text: "download", link: "/zh/developer/install/cli/backups-download"},
{text: "region", link: "/zh/developer/install/cli/backups-region"},
{text: "backup", link: "/zh/developer/install/cli/backups-backup"},
@ -598,62 +597,55 @@ const side = {
},
],
},
],
},
{
text: "change-ip",
link: "/zh/developer/install/cli/change-ip",
},
{
text: "download",
link: "/zh/developer/install/cli/download",
},
{text: "info", link: "/zh/developer/install/cli/info"},
{
text: "install",
link: "/zh/developer/install/cli/install",
},
{
text: "logs",
link: "/zh/developer/install/cli/logs",
},
{
text: "precheck",
link: "/zh/developer/install/cli/precheck",
},
{
text: "prepare",
link: "/zh/developer/install/cli/prepare",
},
{
text: "release",
link: "/zh/developer/install/cli/release",
},
{
text: "start",
link: "/zh/developer/install/cli/start",
},
{
text: "stop",
link: "/zh/developer/install/cli/stop",
},
{
text: "uninstall",
link: "/zh/developer/install/cli/uninstall",
},
],
},
{
text: "版本说明",
link: "/zh/developer/install/versioning",
},
{
text: "其他安装方式",
link: "/zh/developer/install/additional-installations",
collapsed: true,
items: [
{ text: "LinuxDocker 镜像)", link: "/zh/developer/install/linux-via-docker-compose" },
{
text: "macOS",
collapsed: true,
items: [
{
text: "使用脚本(推荐)",
link: "/zh/developer/install/mac",
},
{
text: "使用 Docker 镜像",
link: "/zh/developer/install/mac-via-docker-image",
},
],
},
{
text: "Windows (WSL 2)",
collapsed: true,
items: [
{
text: "使用脚本(推荐)",
link: "/zh/developer/install/windows",
},
{
text: "使用 Docker 镜像",
link: "/zh/developer/install/windows-via-docker-image",
},
],
},
{
text: "PVE",
collapsed: true,
items: [
{
text: "使用脚本(推荐)",
link: "/zh/developer/install/pve",
},
{
text: "使用 ISO 镜像",
link: "/zh/developer/install/pve-via-iso-image",
},
],
},
{ text: "LXC", link: "/zh/developer/install/lxc" },
{ text: "树莓派", link: "/zh/developer/install/raspberry-pi" },
],
},
],
},
{
@ -890,8 +882,8 @@ const side = {
},
],
},
],
};
],
};
export const zh = defineConfig({
lang: "zh",
@ -903,7 +895,7 @@ export const zh = defineConfig({
{ text: "Olares", link: "zh/manual/overview" },
{ text: "Olares Space", link: "/zh/space/" },
{ text: "应用示例", link: "/zh/use-cases/" },
{ text: "开发者文档", link: "/zh/developer/install/" },
{ text: "开发者文档", link: "/zh/developer/concepts/" },
],
sidebar: side,

View file

@ -45,7 +45,7 @@ Olares supports unified authentication for a multi-user system.
2. Each user request first goes through the Authelia service for authentication.
3. If authentication fails, the application redirects the user to the login page to re-authenticate.
4. If authentication succeeds, the [Backend for Launcher (BFL)](https://github.com/beclab/bfl) attaches the user's basic information and forwards the request to the application service. This relieves the application from handling the authentication itself.
5. For [shared applications](./application.md#shared-applications), developers need to build an additional `Auth Server` to connect the application's account with the BFL account.
5. For [shared applications](application.md#shared-applications), developers need to build an additional `Auth Server` to connect the application's account with the BFL account.
## Multi-factor authentication (MFA)
@ -63,9 +63,9 @@ When users perform sensitive operations such as login, Olares requires users to
### Users
- [Create Olares ID](../get-started/create-olares-id)
- [User roles and permissions](../olares/settings/roles-permissions.md)
- [Create Olares ID](../../manual/get-started/create-olares-id.md)
- [User roles and permissions](../../manual/olares/settings/roles-permissions.md)
### Developers
- [Account system callback](../../developer/develop/advanced/account.md)
- [Account system callback](../develop/advanced/account.md)

View file

@ -65,7 +65,7 @@ Olares supports multiple users and provides two distinct namespaces for system a
System applications and user's built-in applications are generally restricted from direct access by third-party applications.
However, if built-in applications or database clusters make specific service interfaces available through a [service provider](../../developer/develop/advanced/provider.md), community applications can request access by [declaring these permissions](../../developer/develop/package/manifest.md#sysdata).
However, if built-in applications or database clusters make specific service interfaces available through a [service provider](../develop/advanced/provider.md), community applications can request access by [declaring these permissions](../develop/package/manifest.md#sysdata).
When such access is granted, the system routes these network requests through secure proxies in the `user-system` namespace, ensuring proper authentication and protection of resources.
@ -122,8 +122,8 @@ The mechanism consists of three procedures
- User
[Manage apps in Market](../olares/market.md)<br>
[Manage apps in Market](../../manual/olares/market.md)<br>
- Developer
[Learn to develop applications on Olares](../../developer/develop/index.md)<br>
[Learn to develop applications on Olares](../develop/index.md)<br>

View file

@ -30,7 +30,7 @@ Olares OS uses [JuiceFS](https://juicefs.com) as the underlying multi-physical n
As for the back-end object storage solution of JuiceFS, we also provide two solutions: S3 and MinIO.
By default, Olares uses the local file system (FS) when installed locally. However, if the `--with-juicefs=true` option is specified when running the [`olares-cli prepare`](../../developer/install/cli/prepare.md) command, JuiceFS will be installed and used. Additionally, a MinIO instance will be set up as the backend storage.
By default, Olares uses the local file system (FS) when installed locally. However, if the `--with-juicefs=true` option is specified when running the [`olares-cli prepare`](../install/cli/prepare.md) command, JuiceFS will be installed and used. Additionally, a MinIO instance will be set up as the backend storage.
### Local disk
@ -46,33 +46,33 @@ For applications, there are 3 different storage paths to deal with different usa
The `UserData` storage path stores files that change infrequently but require cross-application access, such as documents, photos, and videos.
Applications can obtain access permissions to a directory under the Home directory by applying for [UserData](../../developer/develop/package/manifest.md#userdata) permissions in `OlaresManifest.yaml`. For example, you can request permissions to the Picture directory for PhotoPrism, and permissions to the Downloads directory for qBittorrent and Jellyfin.
Applications can obtain access permissions to a directory under the Home directory by applying for [UserData](../develop/package/manifest.md#userdata) permissions in `OlaresManifest.yaml`. For example, you can request permissions to the Picture directory for PhotoPrism, and permissions to the Downloads directory for qBittorrent and Jellyfin.
### AppData
The `AppData` storage path stores data that does not change frequently but needs to span across nodes. For example, configuration files.
Applications can apply for [AppData](../../developer/develop/package/manifest.md#appdata) permissions in `OlaresManifest.yaml`.
Applications can apply for [AppData](../develop/package/manifest.md#appdata) permissions in `OlaresManifest.yaml`.
### AppCache
The `AppCache` storage path is allocated for applications that directly operate the disk with good performance. The disadvantage is that it cannot be accessed across nodes. For example, the system database, application log, and cache.
Applications can apply for [AppCache](../../developer/develop/package/manifest.md#appcache) permissions in `OlaresManifest.yaml`.
Applications can apply for [AppCache](../develop/package/manifest.md#appcache) permissions in `OlaresManifest.yaml`.
## [PostgreSQL](../../developer/develop/advanced/database.md#rds)
## [PostgreSQL](../develop/advanced/database.md#rds)
As one of the most popular open-source relational databases, PostgreSQL has excellent performance and rich plug-in functions. Olares OS deploys PostgreSQL on the system along with the popular Citus distributed database plug-in. At the same time, its cluster is managed through the PG Operator in the TAPR component. Users can easily expand the number of PostgreSQL nodes, and back up or restore data along with the entire Olares system.
If the PostgreSQL database application declared by the developer in the application is Distributed, then Olares will build its database on Citus, allowing the application to fully utilize the capabilities of the distributed PG database.
## [MongoDB](../../developer/develop/advanced/database.md#nosql)
## [MongoDB](../develop/advanced/database.md#nosql)
MongoDB, as a representative of NoSQL, has a wide range of application scenarios in the Internet of Things field. By deploying [Percona Operator for MongoDB](https://github.com/percona/percona-server-mongodb-operator), developers have a cloud-native version of MongoDB cluster in Olares.
Like PostgreSQL, Olares also manages MongoDB backup and restore in a unified manner. Users do not need to have any DBA technical capabilities to easily implement functions such as scheduled backup, incremental backup, and fixed-point restore.
## [Redis](../../developer/develop/advanced/database.md#cache)
## [Redis](../develop/advanced/database.md#cache)
There is no doubt that Redis can be regarded as the most popular memory cache software currently. It has rich instructions and derives a variety of data types based on Key-Value data. Many systems even use it as KV data storage. Olares OS also deploys a customized [Redis Cluster Operator](https://github.com/beclab/redis-cluster-operator) in the system, providing a cloud-native version of Redis Cluster.
@ -104,7 +104,7 @@ The Backup component also has data restoration capabilities. You can download a
- User
[Manage files](../olares/files/index.md)<br>
[Manage files](../../manual/olares/files/index.md)<br>
[Back up and restore](../../space/backup-restore.md)
- Developer

View file

@ -13,11 +13,11 @@ The Concepts section helps you learn about the parts of the Olares system and ob
Understand Olares with the following concepts:
- [Architectural components](system-architecture.md)
- [Olares ID](./olares-id.md)
- [Account](./account.md)
- [Application](./application.md)
- [Network](./network.md)
- [Data](./data.md)
- [Secrets](./secrets.md)
- [Olares ID](olares-id.md)
- [Account](account.md)
- [Application](application.md)
- [Network](network.md)
- [Data](data.md)
- [Secrets](secrets.md)

View file

@ -60,7 +60,7 @@ A route ID is a unique identifier used to identify specific applications or appl
::: tip Note
- The URL of the application is derived from Olares ID.
- Entrance index refers to the position of entrance in multiple entrances defined in [`OlaresManifest.yaml`](../../developer/develop/package/manifest.md).
- Entrance index refers to the position of entrance in multiple entrances defined in [`OlaresManifest.yaml`](../develop/package/manifest.md).
:::
## Olares internal network
@ -93,5 +93,5 @@ Inside the application, Olares has multiple layers of security.
## Learn more
- [Set up custom domain name for application](../olares/settings/custom-app-domain.md#custom-domain-name)
- [Set up custom domain name for application](../../manual/olares/settings/custom-app-domain.md#custom-domain-name)
- [Access Olares via VPN](/manual/larepass/private-network.md)

View file

@ -70,6 +70,6 @@ Each Olares ID is bound to a DID. When a user creates an account using Olares, a
## Learn more
* [Create an Olares ID](../get-started/create-olares-id)
* [Create an Olares ID](../../manual/get-started/create-olares-id)
* [Decentralized identifier (DID)](did.md)
* [Gmail issuer service](/developer/contribute/olares-id/verifiable-credential/olares.md#gmail-issuer-service)

View file

@ -5,11 +5,11 @@ description: Olares secrets management system principles, detailing vault items,
Olares categorizes secrets based on usage scenarios and employs various management techniques.
| | Data Type | Storage Location | Leak Risk | Usage |
|-------------|----------------------------------------------------------------------------------------------------------|-------------------------------------|-------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|
| | Data Type | Storage Location | Leak Risk | Usage |
|-------------|----------------------------------------------------------------------------------------------------------|-------------------------------------|---------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|
| Vault items | Includes website and <br/>database passwords, <br/>blockchain private <br/>keys, etc. | Vault | Encrypted data in Olares ensures that third parties cannot view even upon logging in | Each use requires a signature from LarePass |
| Credentials | System access <br/>credentials obtained<br/> post-secure<br/> authentication:<br/> Tokens, Cookies, etc. | [Infisical](https://infisical.com/) | Viewable by third parties post-authentication in Olares by following specific steps | Available to applications through an API after obtaining Provider permissions |
| Secret | Sensitive data used<br/> in Pod containers,<br/> like database <br/>connections and <br/> admin accounts | ETCD | Directly visible in [Control Hub](../olares/controlhub/manage-workload#secrets) | Used in Helm deployment templates; secret values are injected into environment variables via valueFrom -> secretKeyRef |
| Secret | Sensitive data used<br/> in Pod containers,<br/> like database <br/>connections and <br/> admin accounts | ETCD | Directly visible in [Control Hub](../../manual/olares/controlhub/manage-workload) | Used in Helm deployment templates; secret values are injected into environment variables via valueFrom -> secretKeyRef |
## Integration credential
@ -18,9 +18,9 @@ Users can enable applications within Olares to access external service credentia
- Logging in to Olares Space allows the backup service to request tokens for automated backend backups.
- Logging into Google enables Files to synchronize with data from Google Drive.
Applications in Olares can retrieve these third-party service credentials via the [Service Provider](../../developer/develop/advanced/provider.md).
Applications in Olares can retrieve these third-party service credentials via the [Service Provider](../develop/advanced/provider.md).
## Application credential
- Applications within Olares can manage and utilize [credentials](../../developer/develop/advanced/secret.md) via system-provided interfaces.
- Applications within Olares can manage and utilize [credentials](../develop/advanced/secret.md) via system-provided interfaces.
- Credentials generated by an application are exclusively restricted to that application's use.

View file

@ -59,14 +59,14 @@ Currently, Olares GPU support is restricted to deployments with one GPU per node
Starting with Olares v1.11, [CUDA](https://developer.nvidia.com/cuda-toolkit) (12.4 and above) is supported. Changes in the host environment's CUDA configuration can be synchronized with the Olares cluster using `olares-cli`.
### Container management
Olares uses [containerd](../../developer/install/installation-overview.md#container-runtime-containerd), a lightweight container runtime, for containerized deployments.
Olares uses [containerd](../install/installation-overview.md#container-runtime-containerd), a lightweight container runtime, for containerized deployments.
### Olares Controller Panel
The management of Olares is implemented through the following:
- [olares-cli](../../developer/install/cli/olares-cli.md): A command-line tool for managing Olares clusters, applications, and hardware nodes.
- [olaresd](../../developer/install/installation-overview.md#container-runtime-containerd): A daemon process that monitors hardware and network changes, while also managing cluster upgrades, restarts, and other maintenance operations.
- [olares-cli](../install/cli/olares-cli.md): A command-line tool for managing Olares clusters, applications, and hardware nodes.
- [olaresd](../install/installation-overview.md#container-runtime-containerd): A daemon process that monitors hardware and network changes, while also managing cluster upgrades, restarts, and other maintenance operations.
These tools streamline installation, maintenance, and scaling for Olares.
@ -215,6 +215,6 @@ The console for Olares, providing precise and autonomous control over the system
A development tool for building and deploying Olares applications.
## Learn more
- To get started with Olares, see the [Getting Started guide](../get-started/index.md).
- To get started with Olares, see the [Getting Started guide](../../manual/get-started/index.md).
- To learn more about the internals of Olares, see the topics in [Concept](index.md).
- For in-depth details about how each component of Olares is orchestrated, see [Olares installation overview](../../developer/install/index.md).
- For in-depth details about how each component of Olares is orchestrated, see [Olares installation overview](../install/index.md).

View file

@ -16,7 +16,7 @@ When users creates a Olares account, a DID is automatically generated in the beg
- Backup/Import Olares IDs with a mnemonic phrase for quick setup and account recovery
- Manage multiple DIDs/Olares IDs
See [Manage Accounts with LarePass](https://docs.olares.com/how-to/LarePass/account/) for more detailed information.
See [Manage Accounts with LarePass](../../manual/larepass/create-account.md) for more detailed information.
## Manage VCs
@ -25,4 +25,4 @@ LarePass allows users to manage their VCs that are bound to Olares IDs, enabling
![VC management](/images/manual/concepts/vc-management.png)
::: tip NOTE
These are just the core implementations of LarePass that are closely related to the identity wallet. For more details on LarePass and its usages, refer to the [LarePass documentation](https://docs.olares.com/how-to/LarePass/overview.html).
These are just the core implementations of LarePass that are closely related to the identity wallet. For more details on LarePass and its usages, refer to the [LarePass documentation](../../manual/larepass/).

View file

@ -6,14 +6,14 @@ outline: [1, 5]
Snowinning Protocol's smart contract has two parts.
- [TerminusDID](https://github.com/beclab/terminusdid-contract-system/blob/main/src/core/TerminusDID.sol) contract plays a crucial role as the [DID Registry](/manual/concepts/registry.md). Learn more in [the contract](https://optimistic.etherscan.io/address/0x5da4fa8e567d86e52ef8da860de1be8f54cae97d).
- [TerminusDID](https://github.com/beclab/terminusdid-contract-system/blob/main/src/core/TerminusDID.sol) contract plays a crucial role as the [DID Registry](/developer/concepts/registry.md). Learn more in [the contract](https://optimistic.etherscan.io/address/0x5da4fa8e567d86e52ef8da860de1be8f54cae97d).
- Third-party protocols that extend the reputation system based on [TerminusDID](https://github.com/beclab/terminusdid-contract-system/blob/main/src/core/TerminusDID.sol). Currently, the following reputation protocols are in place:
- [Otmoic Trader Reputation](https://github.com/otmoic/reputation-contract-evm/blob/main/contracts/Reputation.sol). Learn more in [the contract](https://optimistic.etherscan.io/address/0x3179CE5fAB68C0286Da85f3d61BcE7116815e799).
- [Application Reputation](https://github.com/beclab/terminusdid-contract-system/blob/main/src/taggers/TerminusAppMarketReputation.sol). Learn more in [the contract](https://optimistic.etherscan.io/address/0x08065353D266121938B93D4B1071Bb52CD0C0EE4).
![alt text](/images/developer/contribute/smart-contract.jpg)
- The [TerminusDID](https://github.com/beclab/terminusdid-contract-system/blob/main/src/core/TerminusDID.sol) contract plays a crucial role, and it serves as the [DID Registry](/manual/concepts/registry.md). View [the contract](https://optimistic.etherscan.io/address/0x5da4fa8e567d86e52ef8da860de1be8f54cae97d).
- The [TerminusDID](https://github.com/beclab/terminusdid-contract-system/blob/main/src/core/TerminusDID.sol) contract plays a crucial role, and it serves as the [DID Registry](/developer/concepts/registry.md). View [the contract](https://optimistic.etherscan.io/address/0x5da4fa8e567d86e52ef8da860de1be8f54cae97d).
- Third-party protocols can extend the reputation based on [TerminusDID](https://github.com/beclab/terminusdid-contract-system/blob/main/src/core/TerminusDID.sol). Currently, the following reputation protocols are in place:
- [Otmoic Trader Reputation](https://github.com/otmoic/reputation-contract-evm/blob/main/contracts/Reputation.sol). View [the contract](https://optimistic.etherscan.io/address/0xE924F7f68D1dcd004720e107F62c6303aF271ed3).
- [Application Reputation](https://github.com/beclab/terminusdid-contract-system/blob/main/src/taggers/TerminusAppMarketReputation.sol). View [the contract](https://optimistic.etherscan.io/address/0x08065353D266121938B93D4B1071Bb52CD0C0EE4).
@ -22,7 +22,7 @@ Snowinning Protocol's smart contract has two parts.
# TerminusDID
The TerminusDID contract manages a hierarchical structure derived from [Domain](/manual/concepts/olares-id.md#domain-types.
The TerminusDID contract manages a hierarchical structure derived from [Domain](/developer/concepts/olares-id.md#domain-types.
![alt text](/images/developer/contribute/smart-contract-tree.jpg)
@ -32,9 +32,9 @@ Each node possesses several default attributes.
| Attribute | Description |
| -------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| name | Specifies the [Domain Name](/manual/concepts/olares-id.md#domain-types). Certain Domain Names can interchange with Terminus Names |
| name | Specifies the [Domain Name](/developer/concepts/olares-id.md#domain-types). Certain Domain Names can interchange with Terminus Names |
| id | Each node is also a NFT, adhering to the **ERC-721** standard. Its id serves as the unique identifier for this NFT, computed through `keccak256(name)` |
| did,owner | The `owner` and `did` of the node, derived from the same mnemonic words. Further details on this can be found [here](/manual/concepts/did.md).<br>. Additionally, storing owner is advantageous because it complies with the **BIP44** specification, facilitating gas-efficient signature verification within EVM contracts. Each node is affiliated with an `owner`, who holds the authority to modify node details. |
| did,owner | The `owner` and `did` of the node, derived from the same mnemonic words. Further details on this can be found [here](/developer/concepts/did.md).<br>. Additionally, storing owner is advantageous because it complies with the **BIP44** specification, facilitating gas-efficient signature verification within EVM contracts. Each node is affiliated with an `owner`, who holds the authority to modify node details. |
| note | Currently, there are three types: Individual, Organization, and Entity |
| allowSubdomain | Indicates whether it is a leaf node. If False, the node cannot spawn further nodes. |
@ -59,15 +59,15 @@ Ownership of different nodes is as follows:
Abstract nodes such as `root`, `com`, `io` belong to the Terminus team.
- **Individual** <br>
`myterminus.com` belongs to the [Individual Domain](/manual/concepts/olares-id.md#domain-types), owned by the Terminus team.
`myterminus.com` belongs to the [Individual Domain](/developer/concepts/olares-id.md#domain-types), owned by the Terminus team.
`alice.myterminus.com` and `bob.myterminus.com` belong to individual Terminus Names, and are owned by the respective users.
- **Organization** <br>
`org1.com` and `org.io` belong to the [Organization Domain](/manual/concepts/olares-id.md#domain-types), owned by the domain admin.
`org1.com` and `org.io` belong to the [Organization Domain](/developer/concepts/olares-id.md#domain-types), owned by the domain admin.
`alice.org1.com` and `bob.org2.io` belong to Organization Terminus Names, and are owned by the respective users.
- **Entity** <br>
The `Application Score` belongs to the [Entity Domain](/manual/concepts/olares-id.md#domain-types), and is owned by the applicant of the entity. Organization admins and users can refer to [Domain Management](../contract/manage/contract.md#register-did) to manage their own nodes and sub-nodes.
The `Application Score` belongs to the [Entity Domain](/developer/concepts/olares-id.md#domain-types), and is owned by the applicant of the entity. Organization admins and users can refer to [Domain Management](../contract/manage/contract.md#register-did) to manage their own nodes and sub-nodes.
:::info
After the project stabilizes, ownership will be transferred to the multisig address of the DAO organization by the Terminus team.
@ -149,7 +149,7 @@ Use the declared address and DID owner to sign the following information in comp
# Reputation
We can create highly flexible [reputation](/manual/concepts/reputation.md) protocols based on Taggers.
We can create highly flexible [reputation](/developer/concepts/reputation.md) protocols based on Taggers.
In implementing an on-chain Reputation system, the most crucial elements are:

View file

@ -11,7 +11,7 @@ The **first-come, first-served** system in Olares ID registration may present so
## VC process for Olares ID
To address the potential faireness concerns, we adopted principles from **Self-Sovereign Identity (SSI)** services proposed by the Web5 team, along with the [VC process](/manual/concepts/vc.md#verification-process) of Olares ID. This led us to design an **Issuer and Verifier** process to assist users in applying for a **Olares ID**.
To address the potential faireness concerns, we adopted principles from **Self-Sovereign Identity (SSI)** services proposed by the Web5 team, along with the [VC process](/developer/concepts/vc.md#verification-process) of Olares ID. This led us to design an **Issuer and Verifier** process to assist users in applying for a **Olares ID**.
![alt text](/images/developer/contribute/vc-process.jpeg)

View file

@ -10,7 +10,7 @@ If you want to engage in lower-level development, read the [protocol standard](#
## Introduction
We have learned about [VC](/manual/concepts/vc.md) and the basic process for applying VCs.
We have learned about [VC](/developer/concepts/vc.md) and the basic process for applying VCs.
Before we get into the implementation details, we can familiarize ourselves with the terms that we will encounter in the real communication process of Wallet, Verifier and Issuer.
| Term | Definition |

View file

@ -2,7 +2,7 @@
Developing applications on Olares is not much different from regular website development. Once you learn a few basic Olares concepts, you can start creating applications on his platform.
- [Core Concepts of Olares](../../manual/concepts/index.md)
- [Core Concepts of Olares](../concepts/index.md)
- [Understanding the Format of Olares Application Chart](./package/chart.md)
- [The structure of the Olares Application Chart](./package/chart.md)
- [Configuration guide and field descriptions of `OlaresManifest.yaml`](./package/manifest.md)

View file

@ -3,7 +3,7 @@
Welcome to the Olares developer guides. These detailed tutorials offer a step-by-step guide on building an Olares Application from scratch.
To get started, you can learn some basic concepts of Olares, such as:
- [Olares architectural components](../../../manual/concepts/architecture.md)
- [Olares architectural components](../../concepts/architecture.md)
- [Olares Application Chart](../../develop/package/chart.md)
- [Olares Extension on Helm](../package/extension.md)

View file

@ -164,9 +164,9 @@ Once your cluster is set up, changes in network configurations can disrupt the m
## Learn more
- [Olares system architecture](../concepts/system-architecture.md#distributed-file-system): Understand the distributed file system that underpins Olares, ensuring scalability, high availability, and seamless data management.
- [Olares system architecture](../../developer/concepts/system-architecture.md#distributed-file-system): Understand the distributed file system that underpins Olares, ensuring scalability, high availability, and seamless data management.
- [The system daemon: olaresd](../../developer/install/installation-overview.md#system-daemon-olaresd): Learn about the central system process that orchestrates and manages core Olares functions.
- [Data](../concepts/data.md#juicefs): Dive into how Olares leverages JuiceFS to provide a unified file system for efficient data storage and retrieval.
- [Data](../../developer/concepts/data.md#juicefs): Dive into how Olares leverages JuiceFS to provide a unified file system for efficient data storage and retrieval.
- [Olares CLI](../../developer/install/cli/olares-cli.md): Explore the command-line interface for managing Olares installation.
- [Olares environment variables](../../developer/install/environment-variables.md): Learn about the environment variables that enable advanced configurations of Olares.
- [Install Olares](../get-started/install-olares.md): Understand how to install and activate Olares.

View file

@ -263,6 +263,6 @@ After completing these steps, your Olares installation will be accessible via yo
## Learn more
- [Olares account](../concepts/account.md)
- [Olares account](../../developer/concepts/account.md)
- [Install Olares](../get-started/install-olares.md)
- [Configure domain rules](../../space/manage-domain.md)

View file

@ -13,7 +13,7 @@ An Olares ID consists of a local name and a domain. For example, in `alice123@ol
- `olares.com`: Domain name
:::tip Olares ID
To learn more about what is Olares ID and why you need one, see [Olares ID](../concepts/olares-id.md).
To learn more about what is Olares ID and why you need one, see [Olares ID](../../developer/concepts/olares-id.md).
:::
## Download and install LarePass app

View file

@ -14,11 +14,11 @@ Before you start, it is recommended to familiarize yourself with a few concepts
| Terminology | Description |
|-----------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [System application](../concepts/application.md#system-applications) | Built-in applications that come pre-installed with Olares,<br/> such as Profile, Files, and Vault. |
| [Community application](../concepts/application.md#community-applications) | Applications that are created and maintained by third-party<br/> developers. |
| [Shared application](../concepts/application.md#cluster-scoped-applications) | A special category of community applications on Olares<br/> designed to provide unified, shared resources or services to all <br/>users within an Olares cluster. Only one <br/>instance is allowed per cluster. |
| [Reference application](../concepts/application.md#reference-applications) | The applications that have been granted access to specific<br/> shared applications |
| [Dependencies](../concepts/application.md#dependencies) | Prerequisite applications that must already be<br/> installed before a user can access an application <br/>that requires them. |
| [System application](../../developer/concepts/application.md#system-applications) | Built-in applications that come pre-installed with Olares,<br/> such as Profile, Files, and Vault. |
| [Community application](../../developer/concepts/application.md#community-applications) | Applications that are created and maintained by third-party<br/> developers. |
| [Shared application](../../developer/concepts/application.md#cluster-scoped-applications) | A special category of community applications on Olares<br/> designed to provide unified, shared resources or services to all <br/>users within an Olares cluster. Only one <br/>instance is allowed per cluster. |
| [Reference application](../../developer/concepts/application.md#reference-applications) | The applications that have been granted access to specific<br/> shared applications |
| [Dependencies](../../developer/concepts/application.md#dependencies) | Prerequisite applications that must already be<br/> installed before a user can access an application <br/>that requires them. |
## Find applications
The Olares Market offers various ways to discover and browse applications.

View file

@ -11,8 +11,8 @@ You can access Olares applications anytime, anywhere, whether you're accessing f
## Before you begin
Before you start, it is recommended to familiarize yourself with a few concepts for Olares applications:
- [Endpoints](../../concepts/network.md#endpoints)
- [Route ID](../../concepts/network.md#route-id)
- [Endpoints](../../../developer/concepts/network.md#endpoints)
- [Route ID](../../../developer/concepts/network.md#route-id)
## Customize domain name for application

View file

@ -5,7 +5,7 @@ description: Learn how to manage application entrances in Olares, including sett
# Manage application entrances
**Entrances** define how users access your applications on Olares. For a deeper understanding, refer to the [Entrance concept](../../concepts/network.md#entrance) section.
**Entrances** define how users access your applications on Olares. For a deeper understanding, refer to the [Entrance concept](../../../developer/concepts/network.md#entrance) section.
Entrance management in Olares includes two main components:

View file

@ -27,7 +27,7 @@ Olares follows a model similar to **Android**:
Olares comprises the following core components:
- [**Olares ID**](./concepts/olares-id.md): A decentralized identity and credit system that facilitates secure, trustless exchanges of information and value. It serves as your digital identity across the Olares ecosystem.
- [**Olares ID**](../developer/concepts/olares-id.md): A decentralized identity and credit system that facilitates secure, trustless exchanges of information and value. It serves as your digital identity across the Olares ecosystem.
- [**Olares OS**](https://github.com/beclab/Olares): An open-source, self-hosted operating system that transforms edge devices into robust personal cloud.
@ -73,7 +73,7 @@ Before you roll up your sleeves and get your hands dirty with Olares, feel free
<p class="cta-title">Learn how-tos</p>
<p class="cta-description">Comprehensive system app guides covering daily tasks of using Olares.</p>
</a>
<a href="./concepts/" class="cta-link">
<a href="../developer/concepts/" class="cta-link">
<p class="cta-title">Understand Olares</p>
<p class="cta-description">Grasp the fundamental principles and architecture behind Olares.</p>
</a>

View file

@ -45,7 +45,7 @@ Olares 支持多用户系统的统一认证。
2. 每个用户请求都会先经过 Authelia 服务进行认证。
3. 如果认证失败,应用会将用户重定向到登录页面重新认证。
4. 如果认证成功,[Backend for Launcher (BFL)](https://github.com/beclab/bfl) 会附加用户的基本信息并将请求转发给应用服务。这样应用本身就不需要处理认证逻辑。
5. 对于[共享应用Shared application](./application.md#共享应用),开发者需要构建额外的 `Auth Server` 来连接应用账号与 BFL 账号。
5. 对于[共享应用Shared application](application.md#共享应用),开发者需要构建额外的 `Auth Server` 来连接应用账号与 BFL 账号。
## 多因素认证MFA
@ -63,9 +63,9 @@ Olares 集成了多种不同安全等级的认证因素,以确保系统中用
### 用户
- [创建 Olares ID](../get-started/create-olares-id)
- [用户角色](../olares/settings/roles-permissions.md)
- [创建 Olares ID](../../manual/get-started/create-olares-id.md)
- [用户角色](../../manual/olares/settings/roles-permissions.md)
### 开发者
- [账户系统回调](../../developer/develop/advanced/account.md)
- [账户系统回调](../develop/advanced/account.md)

View file

@ -65,7 +65,7 @@ Olares 支持多用户,并为管理员和普通成员用户提供两个不同
系统应用和用户的内置应用通常不允许第三方应用直接访问。
但如果数据库集群和内置应用通过[ Service Provider](../../developer/develop/advanced/provider.md) 开放了某些接口,社区应用可以通过[声明访问权限](../../developer/develop/package/manifest.md#sysdata)来使用这些服务。
但如果数据库集群和内置应用通过[ Service Provider](../develop/advanced/provider.md) 开放了某些接口,社区应用可以通过[声明访问权限](../develop/package/manifest.md#sysdata)来使用这些服务。
在这种情况下,系统会在 `user-system` 命名空间下为这些资源提供网络代理,并对来自第三方应用的网络请求进行鉴权。
@ -120,9 +120,9 @@ Service Provider 机制使社区应用能够与系统应用、其他社区应用
- 用户
[管理应用](../olares/market.md)<br>
[管理应用](../../manual/olares/market.md)<br>
- 开发者
[在 Olares 上开发应用程序](../../developer/develop/index.md)<br>
[在 Olares 上开发应用程序](../develop/index.md)<br>

View file

@ -30,7 +30,7 @@ Olares 采用 [JuiceFS](https://juicefs.com) 作为底层的多物理节点共
针对 JuiceFS 的后端对象存储方案,我们提供了 S3 和 MinIO 两种选择。
默认情况下Olares 在本地安装时使用本地文件系统FS。不过如果在运行 [`olares-cli prepare`](../../developer/install/cli/prepare.md) 命令时指定了 `--with-juicefs=true` 选项,系统就会安装并使用 JuiceFS同时会搭建一个 MinIO 实例作为后端存储。
默认情况下Olares 在本地安装时使用本地文件系统FS。不过如果在运行 [`olares-cli prepare`](../install/cli/prepare.md) 命令时指定了 `--with-juicefs=true` 选项,系统就会安装并使用 JuiceFS同时会搭建一个 MinIO 实例作为后端存储。
### 本地磁盘
@ -46,33 +46,33 @@ Olares 提供的最佳实践是充分利用节点的本地硬盘作为文件缓
`UserData` 存储路径用于存放变动不频繁但需要跨应用访问的文件,如文档、照片和视频等。
应用可以通过在 `OlaresManifest.yaml` 中申请 [UserData](../../developer/develop/package/manifest.md#userdata) 权限来获取 `Home` 目录下某个目录的访问权限。比如 PhotoPrism 可以申请 `Picture` 目录的权限qBittorrent 和 Jellyfin 可以申请 `Downloads` 目录的权限。
应用可以通过在 `OlaresManifest.yaml` 中申请 [UserData](../develop/package/manifest.md#userdata) 权限来获取 `Home` 目录下某个目录的访问权限。比如 PhotoPrism 可以申请 `Picture` 目录的权限qBittorrent 和 Jellyfin 可以申请 `Downloads` 目录的权限。
### AppData
`AppData` 存储路径用于存放变动不频繁但需要跨节点的数据,比如配置文件。
应用可以在 `OlaresManifest.yaml` 中申请 [AppData](../../developer/develop/package/manifest.md#appdata) 权限。
应用可以在 `OlaresManifest.yaml` 中申请 [AppData](../develop/package/manifest.md#appdata) 权限。
### AppCache
`AppCache` 存储路径分配给需要直接操作磁盘且性能要求较好的应用。比如系统数据库、应用日志和缓存等。缺点是无法跨节点访问。
应用可以在 `OlaresManifest.yaml` 中申请 [AppCache](../../developer/develop/package/manifest.md#appcache) 权限。
应用可以在 `OlaresManifest.yaml` 中申请 [AppCache](../develop/package/manifest.md#appcache) 权限。
## [PostgreSQL](../../developer/develop/advanced/database.md#rds)
## [PostgreSQL](../develop/advanced/database.md#rds)
作为最受欢迎的开源关系型数据库之一PostgreSQL 具有出色的性能和丰富的插件功能。Olares 在系统中部署了 PostgreSQL同时集成了广受欢迎的 Citus 分布式数据库插件。通过 Olares 应用运行时组件中的 PG Operator 进行集群管理,用户可以轻松扩展 PostgreSQL 节点数量,并随整个 Olares 系统进行备份或恢复。
如果开发者在应用中声明的 PostgreSQL 数据库为分布式类型,那么 Olares 会在 Citus 上构建其数据库,让应用充分利用分布式 PG 数据库的能力。
## [MongoDB](../../developer/develop/advanced/database.md#nosql)
## [MongoDB](../develop/advanced/database.md#nosql)
MongoDB 作为 NoSQL 的代表,在物联网领域有着广泛的应用场景。通过部署 [Percona Operator for MongoDB](https://github.com/percona/percona-server-mongodb-operator),开发者在 Olares 中就拥有了云原生版本的 MongoDB 集群。
与 PostgreSQL 一样Olares 也统一管理 MongoDB 的备份和恢复。用户无需具备任何 DBA 技术能力,就能轻松实现定时备份、增量备份、定点恢复等功能。
## [Redis](../../developer/develop/advanced/database.md#cache)
## [Redis](../develop/advanced/database.md#cache)
毫无疑问Redis 可以说是目前最受欢迎的内存缓存软件。它拥有丰富的指令,并基于 Key-Value 数据衍生出多种数据类型。很多系统甚至将其作为 KV 数据存储使用。Olares 也在系统中部署了定制的 [Redis Cluster Operator](https://github.com/beclab/redis-cluster-operator),提供云原生版本的 Redis 集群。
@ -104,9 +104,9 @@ Olares 同样接管了 Redis 集群的备份和恢复工作,用户无需为 Re
- 用户
[文件管理](../olares/files/index.md)<br>
[文件管理](../../manual/olares/files/index.md)<br>
[备份与恢复](../../space/backup-restore.md)
- 开发者
[文件上传](../../developer/develop/advanced/file-upload.md)<br>
[文件上传](../develop/advanced/file-upload.md)<br>

View file

@ -13,11 +13,11 @@ description: Olares 系统核心概念说明文档,阐述架构设计、身份
通过以下概念来理解 Olares
- [架构](system-architecture.md)
- [Olares ID](./olares-id.md)
- [账户](./account.md)
- [应用](./application.md)
- [网络](./network.md)
- [数据](./data.md)
- [密钥](./secrets.md)
- [Olares ID](olares-id.md)
- [账户](account.md)
- [应用](application.md)
- [网络](network.md)
- [数据](data.md)
- [密钥](secrets.md)

View file

@ -57,7 +57,7 @@ Olares 为用户提供无障碍且安全灵活的网络解决方案。本文档
::: tip 注意
- 应用地址包含 Olares ID
- 入口索引指的是入口在 [`OlaresManifest.yaml`](../../developer/develop/package/manifest.md) 中定义的多个入口中的位置。
- 入口索引指的是入口在 [`OlaresManifest.yaml`](../develop/package/manifest.md) 中定义的多个入口中的位置。
:::
## Olares 内部网络
@ -90,5 +90,5 @@ Olares 在网关架构中采用多层代理路由设计。流量经过多个层
## 了解更多
- [为应用设置自定义域名](../olares/settings/custom-app-domain.md#自定义域名)
- [通过专用网络访问 Olares 应用](../larepass/private-network.md)
- [为应用设置自定义域名](../../manual/olares/settings/custom-app-domain.md#自定义域名)
- [通过专用网络访问 Olares 应用](../../manual/larepass/private-network.md)

View file

@ -51,8 +51,8 @@ Olares 提供三类域名:
### 个人 Olares ID 创建方式
- **[快速创建](../larepass/create-account.md#快速创建)**:选择一个可用的本地名立即生成 ID。
- **[高级创建](../larepass/create-account.md#高级创建)**:使用可验证凭证 (VC) 将现有可信身份(如邮箱)绑定至 Olares ID。
- **[快速创建](../../manual/larepass/create-account.md#快速创建)**:选择一个可用的本地名立即生成 ID。
- **[高级创建](../../manual/larepass/create-account.md#高级创建)**:使用可验证凭证 (VC) 将现有可信身份(如邮箱)绑定至 Olares ID。
- 通过 OAuth 验证
- 将社交身份与 Olares DID 建立加密关联
@ -64,6 +64,6 @@ Olares ID 采用类似邮箱的可读格式,使 DID 更易用,同时保持
## 深入阅读
- [创建 Olares ID](../larepass/create-account.md)
- [创建 Olares ID](../../manual/larepass/create-account.md)
- [去中心化标识符 (DID)](did.md)
- [Gmail issuer 服务](/zh/developer/contribute/olares-id/verifiable-credential/olares.md#gmail-issuer-service)

View file

@ -9,7 +9,7 @@ Olares 根据使用场景对密钥进行分类并采用不同的管理方式。
|----------|-------------------------------------|------------------------------------|-----------------------------------------------------|--------------------------------------------------|
| Vault 项目 | 包括网站密码、数<br/>据库密码、区块链<br/>私钥等 | Vault | Olares 中的加密数据确保第三方即使登录也无法查看 | 每次使用都需要 LarePass 签名 |
| 凭证 | 安全认证后获取<br/>的系统访问凭据:<br/>令牌、Cookie 等 | [Infisical](https://infisical.com/) | 第三方在 Olares 中通过特定步骤认证后可查看 | 应用程序获得 Provider 权限后可通过 API 使用 |
| 密钥 | Pod 容器中使用的<br/>敏感数据,如数据<br/>库连接和管理账号 | ETCD | 可在[控制面板](../olares/controlhub/manage-workload.md#保密字典)直接查看 | 用于 Helm 部署模板,通过 `valueFrom -> secretKeyRef` 注入环境变量 |
| 密钥 | Pod 容器中使用的<br/>敏感数据,如数据<br/>库连接和管理账号 | ETCD | 可在[控制面板](../../manual/olares/controlhub/manage-workload.md#保密字典)直接查看 | 用于 Helm 部署模板,通过 `valueFrom -> secretKeyRef` 注入环境变量 |
## 集成凭据
@ -18,9 +18,9 @@ Olares 根据使用场景对密钥进行分类并采用不同的管理方式。
- 登录 Olares Space 后,备份服务可以请求令牌用于自动后台备份
- 登录 Google 后,文件功能可以与 Google Drive 中的数据同步
Olares 中的应用程序可以通过[Service Provider](../../developer/develop/advanced/provider.md) 获取这些第三方服务凭据。
Olares 中的应用程序可以通过[Service Provider](../develop/advanced/provider.md) 获取这些第三方服务凭据。
## 应用凭据
- Olares 中的应用可以通过系统提供的接口管理和使用[密钥](../../developer/develop/advanced/secret.md)
- Olares 中的应用可以通过系统提供的接口管理和使用[密钥](../develop/advanced/secret.md)
- 应用生成的凭据仅限该应用程序使用

View file

@ -59,14 +59,14 @@ Olares 目前的 GPU 管理功能仅支持单节点单 GPU 的部署场景。
从 Olares v1.11 开始,支持 [CUDA](https://developer.nvidia.com/cuda-toolkit)12.4 及以上版本)。当宿主机环境的 CUDA 配置变更时,可以通过 `olares-cli` 通知 Olares 集群进行配置。
### 容器管理
Olares 使用轻量级容器运行时 [containerd](../../developer/install/installation-overview.md#容器运行时containerd) 进行容器化部署。
Olares 使用轻量级容器运行时 [containerd](../install/installation-overview.md#容器运行时containerd) 进行容器化部署。
### Olares Controller Panel
Olares 的集群管理通过以下工具实现:
- [olares-cli](../../developer/install/cli/olares-cli.md):命令行工具,用于管理 Olares 集群、应用和硬件节点等。
- [olaresd](../../developer/install/installation-overview.md#系统守护进程olaresd)Olares 的守护进程,用于监控硬件和网络变更、处理集群升级和重启等。
- [olares-cli](../install/cli/olares-cli.md):命令行工具,用于管理 Olares 集群、应用和硬件节点等。
- [olaresd](../install/installation-overview.md#系统守护进程olaresd)Olares 的守护进程,用于监控硬件和网络变更、处理集群升级和重启等。
这些工具简化了 Olares 的安装、维护和扩展过程。
@ -215,6 +215,6 @@ Olares 的控制台,提供对系统及其环境的精确和自主控制。
用于构建和部署 Olares 应用的开发工具。
## 了解更多
- 要开始使用 Olares请参阅[快速开始](../get-started/index.md)。
- 要开始使用 Olares请参阅[快速开始](../../manual/get-started/index.md)。
- 要深入了解 Olares 的内部原理,请参阅[概念](index.md)中的主题。
- 要详细了解 Olares 中各组件如何被编排,请参阅 [Olares 安装概述](../../developer/install/index.md)。
- 要详细了解 Olares 中各组件如何被编排,请参阅 [Olares 安装概述](../install/index.md)。

View file

@ -22,7 +22,7 @@ description: 了解数字身份钱包 LarePass 的核心功能,包括 Olares I
- **多身份管理**
同时管理多个 DID / Olares ID
详细说明参见 [使用 LarePass 管理账户](https://docs.olares.com/how-to/LarePass/account/)。
详细说明参见 [使用 LarePass 管理账户](../../manual/larepass/create-account.md)。
## 管理可验证凭证VC
@ -35,5 +35,5 @@ LarePass 支持绑定至 Olares ID 的 VC 全流程操作,包括签名、验
- **发现与检索**:便捷查看各身份对应的 VC 列表
::: tip 说明
以上为 LarePass 与身份钱包相关的核心功能。更多使用方法请参阅 [LarePass 文档](https://docs.olares.com/how-to/LarePass/overview.html)。
以上为 LarePass 与身份钱包相关的核心功能。更多使用方法请参阅 [LarePass 文档](../../manual/larepass/)。
:::

View file

@ -2,26 +2,26 @@
Olares ID 的智能合约包含两个部分。
- [TerminusDID](https://github.com/beclab/terminusdid-contract-system/blob/main/src/core/TerminusDID.sol) 合约扮演着关键角色,并作为 [DID Registry (DID 注册表)](https://www.google.com/search?q=/manual/concepts/registry.md)。查看[合约](https://optimistic.etherscan.io/address/0x5da4fa8e567d86e52ef8da860de1be8f54cae97d)。
- [TerminusDID](https://github.com/beclab/terminusdid-contract-system/blob/main/src/core/TerminusDID.sol) 合约扮演着关键角色,并作为 [DID Registry (DID 注册表)](/developer/concepts/registry.md)。查看[合约](https://optimistic.etherscan.io/address/0x5da4fa8e567d86e52ef8da860de1be8f54cae97d)。
- 第三方协议可以基于 [TerminusDID](https://github.com/beclab/terminusdid-contract-system/blob/main/src/core/TerminusDID.sol) 扩展信誉系统。目前,已部署以下信誉协议:
- [Otmoic Trader Reputation](https://github.com/otmoic/reputation-contract-evm/blob/main/contracts/Reputation.sol)。查看[合约](https://optimistic.etherscan.io/address/0xE924F7f68D1dcd004720e107F62c6303aF271ed3)。
- [Application Reputation](https://github.com/beclab/terminusdid-contract-system/blob/main/src/taggers/TerminusAppMarketReputation.sol)。查看[合约](https://optimistic.etherscan.io/address/0x08065353D266121938B93D4B1071Bb52CD0C0EE4)。
# TerminusDID
TerminusDID 合约管理着一个源自 [Domain (域)](https://docs.jointerminus.com/overview/terminus/terminus-name.html#domain) 的层级结构。
TerminusDID 合约管理着一个源自 [Domain (域)](/zh/developer/concepts/olares-id.md#domain) 的层级结构。
## 节点 (Node)
每个节点都拥有几个默认属性。
| 属性 | 描述 |
| ---------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| name | 指定[域名 (Domain Name)](/zh/manual/concepts/olares-id#域名类型)。某些域名可与 Olares ID 互换。 |
| id | 每个节点也是一个遵循 **ERC-721** 标准的 NFT。其 id 是该 NFT 的唯一标识符,通过 `keccak256(name)` 计算得出。 |
| did,owner | 节点的 `owner``did`,由相同的助记词派生而来。更多详情请见[此处](https://www.google.com/search?q=/manual/concepts/did.md)。\<br\>此外,存储 owner 的好处在于它遵循 **BIP44** 规范,有助于在 EVM 合约内进行节省 Gas 的签名验证。每个节点都隶属于一个 `owner`,该 `owner` 有权修改节点详情。 |
| note | 目前有三种类型:个人 (Individual)、组织 (Organization) 和实体 (Entity)。 |
| allowSubdomain | 指示其是否为叶子节点。如果为 False该节点无法派生更多子节点。 |
| 属性 | 描述 |
| ---------------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| name | 指定[域名 (Domain Name)](/zh/developer/concepts/olares-id#域名类型)。某些域名可与 Olares ID 互换。 |
| id | 每个节点也是一个遵循 **ERC-721** 标准的 NFT。其 id 是该 NFT 的唯一标识符,通过 `keccak256(name)` 计算得出。 |
| did,owner | 节点的 `owner``did`,由相同的助记词派生而来。更多详情请见[此处](/zh/developer/concepts/did.md)。\<br\>此外,存储 owner 的好处在于它遵循 **BIP44** 规范,有助于在 EVM 合约内进行节省 Gas 的签名验证。每个节点都隶属于一个 `owner`,该 `owner` 有权修改节点详情。 |
| note | 目前有三种类型:个人 (Individual)、组织 (Organization) 和实体 (Entity)。 |
| allowSubdomain | 指示其是否为叶子节点。如果为 False该节点无法派生更多子节点。 |
以下是一个指定节点默认属性的示例:
@ -44,15 +44,15 @@ TerminusDID 合约管理着一个源自 [Domain (域)](https://docs.jointerminus
诸如 `root`、`com`、`io` 等抽象节点属于 Terminus 团队。
- **个人 (Individual)** \<br\>
`myterminus.com` 属于[个人域 (Individual Domain)](/zh/manual/concepts/olares-id.md#域名类型),由 Terminus 团队所有。
`myterminus.com` 属于[个人域 (Individual Domain)](/zh/developer/concepts/olares-id.md#域名类型),由 Terminus 团队所有。
`alice.myterminus.com``bob.myterminus.com` 属于个人 Terminus 名称,由各自的用户所有。
- **组织 (Organization)** \<br\>
`org1.com``org.io` 属于[组织域 (Organization Domain)](/zh/manual/concepts/olares-id.md#域名类型),由域管理员所有。
`org1.com``org.io` 属于[组织域 (Organization Domain)](/zh/developer/concepts/olares-id.md#域名类型),由域管理员所有。
`alice.org1.com``bob.org2.io` 属于组织 Terminus 名称,由各自的用户所有。
- **实体 (Entity)** \<br\>
`Application Score` 属于[实体域 (Entity Domain)](/zh/manual/concepts/olares-id.md#域名类型),由该实体的申请人所有。组织管理员和用户可以参考[域管理](https://www.google.com/search?q=../contract/manage/contract.md%23register-did)来管理他们自己的节点和子节点。
`Application Score` 属于[实体域 (Entity Domain)](/zh/developer/concepts/olares-id.md#域名类型),由该实体的申请人所有。组织管理员和用户可以参考[域管理](https://www.google.com/search?q=../contract/manage/contract.md%23register-did)来管理他们自己的节点和子节点。
:::info
项目稳定后Terminus 团队会将所有权转移给 DAO 组织的多签地址。
@ -132,7 +132,7 @@ Tagger 是每个标签内部的必要信息之一。它代表有权修改标签
# 信誉 (Reputation)
我们可以基于 Tagger 创建高度灵活的[信誉](https://www.google.com/search?q=/manual/concepts/reputation.md)协议。
我们可以基于 Tagger 创建高度灵活的[信誉](/developer/concepts/reputation.md)协议。
在实现链上信誉系统时,最关键的要素是:

View file

@ -11,7 +11,7 @@ Olares ID 注册中的**先到先得**系统可能会带来一些公平性问题
## Olares ID 的 VC 流程
为了解决潜在的公平性问题,我们采纳了 Web5 团队提出的**自主身份 (Self-Sovereign Identity, SSI)** 服务原则,并结合了 Olares ID 的 [VC 流程](/zh/manual/concepts/vc.md#六步验证流程)。这引导我们设计了一个**发行方 (Issuer) 和验证方 (Verifier)** 流程,以协助用户申请 **Olares ID**
为了解决潜在的公平性问题,我们采纳了 Web5 团队提出的**自主身份 (Self-Sovereign Identity, SSI)** 服务原则,并结合了 Olares ID 的 [VC 流程](/zh/developer/concepts/vc.md#六步验证流程)。这引导我们设计了一个**发行方 (Issuer) 和验证方 (Verifier)** 流程,以协助用户申请 **Olares ID**
![alt text](/images/developer/contribute/vc-process.jpeg)

View file

@ -10,7 +10,7 @@
## 简介
我们已经了解了 [VC](/zh/manual/concepts/vc.md) 的概念以及申请 VC 的基本流程。
我们已经了解了 [VC](/zh/developer/concepts/vc.md) 的概念以及申请 VC 的基本流程。
在深入实现细节之前,我们可以先熟悉一下在钱包 (Wallet)、验证方 (Verifier) 和发行方 (Issuer) 的实际通信过程中会遇到的术语。
| 术语 | 定义 |

View file

@ -2,7 +2,7 @@
在 Olares 上开发应用与当下主流的网站开发方法并没有太多区别,只需要额外了解一些 Olares 的基本概念,即可在 Olares 上开发应用。
- [Olares 的核心理念](../../manual/concepts/index.md)
- [Olares 的核心理念](../concepts/index.md)
- [了解 Olares 应用 Chart 的格式](./package/chart.md)
- [Olares 应用 Chart 包的结构](./package/chart.md)
- [OlaresManifest.yaml 的配置和字段说明](./package/manifest.md)

View file

@ -3,7 +3,7 @@
欢迎阅读 Olares 应用开发指南。这些详细的教程将逐步指导你从零开始构建 Olares 应用。
在开始前,你可以先了解一些 Olares 的基本概念,如:
- [Olares 的组成](../../../manual/concepts/architecture.md)
- [Olares 的组成](../../concepts/architecture.md)
- [Olares 应用 Chart](../../develop/package/chart.md)
- [Olares 在 Helm 上的扩展](../package/extension.md)。

View file

@ -162,9 +162,9 @@ olares-cli olares uninstall
## 了解更多
- [Olares 系统架构](../concepts/system-architecture.md#分布式存储):了解支持 Olares 的分布式文件系统,确保可扩展性、高可用性以及无缝的数据管理。
- [Olares 系统架构](../../developer/concepts/system-architecture.md#分布式存储):了解支持 Olares 的分布式文件系统,确保可扩展性、高可用性以及无缝的数据管理。
- [系统守护进程](../../developer/install/installation-overview.md#系统守护进程olaresd)olaresd了解 orchestrates 和管理 Olares 核心功能的中央系统进程。
- [数据](../concepts/data.md#juicefs):探索 Olares 如何利用 JuiceFS 提供统一文件系统,实现高效的数据存储和检索。
- [数据](../../developer/concepts/data.md#juicefs):探索 Olares 如何利用 JuiceFS 提供统一文件系统,实现高效的数据存储和检索。
- [Olares CLI](../../developer/install/cli/olares-cli.md):深入了解用于管理 Olares 安装的命令行工具。
- [Olares 环境变量](../../developer/install/environment-variables.md):了解支持 Olares 高级配置的环境变量。
- [安装 Olares](../get-started/install-olares.md):了解安装与激活 Olares 的过程。

View file

@ -275,6 +275,6 @@ DIDDecentralized Identifier去中心化标识符是在获得最终的 O
## 了解更多
- [Olares 账户](../concepts/account.md)
- [Olares 账户](../../developer/concepts/account.md)
- [安装 Olares](../get-started/install-olares.md)
- [设置域名规则](../../space/manage-domain.md)

View file

@ -10,7 +10,7 @@ Olares ID 由本地名称和域名两部分组成。以 `alice123@olares.cn` 为
- `olares.cn`:域名
:::tip
要了解为什么需要 Olares ID请参阅 [Olares ID](../concepts/olares-id.md)。
要了解为什么需要 Olares ID请参阅 [Olares ID](../../developer/concepts/olares-id.md)。
:::
## 下载并安装 LarePass 应用

View file

@ -58,11 +58,11 @@ description: Olares 新手上路指南,包括系统初始配置、基础功能
title="了解 Olares"
description="加深你对 Olares 的理解。"
:links="[
{ text: 'Olares ID', href: '../../manual/concepts/olares-id' },
{ text: '帐户', href: '../../manual/concepts/account' },
{ text: '应用',href: '../../manual/concepts/application' },
{ text: '网络',href: '../../manual/concepts/network' },
{ text: '数据',href: '../../manual/concepts/data' },
{ text: 'Olares ID', href: '../../developer/concepts/olares-id' },
{ text: '帐户', href: '../../developer/concepts/account' },
{ text: '应用',href: '../../developer/concepts/application' },
{ text: '网络',href: '../../developer/concepts/network' },
{ text: '数据',href: '../../developer/concepts/data' },
]"
buttonText="了解更多"
buttonLink="../concepts/"

View file

@ -13,11 +13,11 @@ description: 通过 Olares 应用市场发现和管理应用,掌握安装更
| 术语 | 描述 |
|-----------------------------------------|--------------------------------------------------------------|
| [系统应用](../concepts/application.md#系统应用) | Olares 内置的预安装应用,例如 Profile、文件管理器和 Vault。 |
| [社区应用](../concepts/application.md#社区应用) | 由第三方开发者创建和维护的应用。 |
| [共享应用](../concepts/application.md#共享应用) | 一种特殊类型的社区应用,向集群范围的授权应用共享服务和资源。 |
| [授权应用](../concepts/application.md#授权应用) | 被授权访问共享应用的一类应用。 |
| [依赖项](../concepts/application.md#依赖项) | 应用需要先安装的前置应用。 |
| [系统应用](../../developer/concepts/application.md#系统应用) | Olares 内置的预安装应用,例如 Profile、文件管理器和 Vault。 |
| [社区应用](../../developer/concepts/application.md#社区应用) | 由第三方开发者创建和维护的应用。 |
| [共享应用](../../developer/concepts/application.md#共享应用) | 一种特殊类型的社区应用,向集群范围的授权应用共享服务和资源。 |
| [授权应用](../../developer/concepts/application.md#授权应用) | 被授权访问共享应用的一类应用。 |
| [依赖项](../../developer/concepts/application.md#依赖项) | 应用需要先安装的前置应用。 |
## 查找应用

View file

@ -9,8 +9,8 @@ description: 自定义 Olares 应用的访问地址,通过设置路由 ID 和
## 开始之前
在开始之前,建议你先熟悉一些与 Olares 应用相关的概念:
- [端点 (Endpoints)](../../concepts/network.md#端点)
- [路由 ID (Route ID)](../../concepts/network.md#路由-id)
- [端点 (Endpoints)](../../../developer/concepts/network.md#端点)
- [路由 ID (Route ID)](../../../developer/concepts/network.md#路由-id)
## 为应用自定义域名

View file

@ -5,7 +5,7 @@ description: 了解如何在 Olares 中管理应用入口,包括设置断点
# 管理应用入口
**入口**定义了用户如何访问 Olares 上的应用。要深入了解,请参阅[入口定义](../../concepts/network.md#入口)。
**入口**定义了用户如何访问 Olares 上的应用。要深入了解,请参阅[入口定义](../../../developer/concepts/network.md#入口)。
入口设置包括两个部分:

View file

@ -26,7 +26,7 @@ Olares 的模式类似于 **Android**
Olares 由以下核心组件组成:
- [Olares ID](./concepts/olares-id.md)一种去中心化的身份与信用系统支持信息和价值的安全、无信任交换。Olares ID 是你在整个 Olares 生态中的数字身份。
- [Olares ID](../developer/concepts/olares-id.md)一种去中心化的身份与信用系统支持信息和价值的安全、无信任交换。Olares ID 是你在整个 Olares 生态中的数字身份。
- [**Olares OS**](https://github.com/beclab/Olares):一个开源自主托管操作系统,可将边缘设备转化为强大的个人云。
@ -76,7 +76,7 @@ Olares 提供了丰富的功能,旨在提升安全性、易用性和开发灵
<p class="cta-title">阅读操作指南</p>
<p class="cta-description">全面了解 Olares 的各个应用。</p>
</a>
<a href="./concepts/" class="cta-link">
<a href="../developer/concepts/" class="cta-link">
<p class="cta-title">了解 Olares</p>
<p class="cta-description">掌握 Olares 的基本原理和架构。</p>
</a>

View file

@ -170,7 +170,7 @@ spec:
priorityClassName: "system-cluster-critical"
containers:
- name: app-service
image: beclab/app-service:0.4.30
image: beclab/app-service:0.4.32
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 0

View file

@ -266,7 +266,7 @@ spec:
containers:
- name: api
image: beclab/bfl:v0.4.31
image: beclab/bfl:v0.4.32
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 1000

View file

@ -179,7 +179,7 @@ spec:
memory: 300Mi
- name: download-server
image: "beclab/download-server:v0.1.10"
image: "beclab/download-server:v0.1.12"
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 0

View file

@ -173,7 +173,7 @@ spec:
{{ end }}
- name: files
image: beclab/files-server:v0.2.123
image: beclab/files-server:v0.2.124
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: true

View file

@ -24,6 +24,43 @@
{{ $pg_password = randAlphaNum 16 | b64enc }}
{{- end -}}
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: market-sa
namespace: {{ .Release.Namespace }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: market-role
rules:
# Access to systemenvs resources
- apiGroups:
- sys.bytetrade.io
resources:
- systemenvs
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: market-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: market-role
subjects:
- kind: ServiceAccount
name: market-sa
namespace: {{ .Release.Namespace }}
---
apiVersion: v1
kind: Secret
@ -79,6 +116,8 @@ spec:
instrumentation.opentelemetry.io/otel-go-auto-target-exe: "/opt/app/market"
{{ end }}
spec:
serviceAccountName: market-sa
serviceAccount: market-sa
priorityClassName: "system-cluster-critical"
initContainers:
- args:
@ -101,7 +140,7 @@ spec:
name: check-chart-repo
containers:
- name: appstore-backend
image: beclab/market-backend:v0.5.3
image: beclab/market-backend:v0.5.4
imagePullPolicy: IfNotPresent
ports:
- containerPort: 81

View file

@ -4,9 +4,9 @@ output:
binaries:
-
id: juicefs
name: juicefs-v11.1.1.tar.gz
amd64: https://github.com/beclab/juicefs-ext/releases/download/v11.1.1/juicefs-v11.1.1-linux-amd64.tar.gz
arm64: https://github.com/beclab/juicefs-ext/releases/download/v11.1.1/juicefs-v11.1.1-linux-arm64.tar.gz
name: juicefs-v1.3.0.tar.gz
amd64: https://github.com/juicedata/juicefs/releases/download/v1.3.0/juicefs-1.3.0-linux-amd64.tar.gz
arm64: https://github.com/juicedata/juicefs/releases/download/v1.3.0/juicefs-1.3.0-linux-arm64.tar.gz