mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2025-08-24 16:05:07 +03:00
Refactor configuration handling by removing writable flag from ConfigInfo and related UI components. Simplify config response structure in WebUIServer and update frontend to reflect these changes. Clean up unused CSS styles for improved layout.
This commit is contained in:
parent
8e44b57879
commit
a094c423de
4 changed files with 26 additions and 118 deletions
|
@ -286,10 +286,9 @@ func (k *KeyBytes) UnmarshalJSON(b []byte) error {
|
|||
|
||||
// ConfigInfo contains information about the configuration file
|
||||
type ConfigInfo struct {
|
||||
Path string `json:"path"`
|
||||
Format string `json:"format"`
|
||||
Data interface{} `json:"data"`
|
||||
Writable bool `json:"writable"`
|
||||
Path string `json:"path"`
|
||||
Format string `json:"format"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// Global variables to track the current configuration state
|
||||
|
@ -338,20 +337,6 @@ func validateConfigPath(path string) (string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Basic sanity check on file extension for config files
|
||||
ext := strings.ToLower(filepath.Ext(absPath))
|
||||
allowedExts := []string{".json", ".hjson", ".conf", ".config", ".yml", ".yaml", ""}
|
||||
validExt := false
|
||||
for _, allowed := range allowedExts {
|
||||
if ext == allowed {
|
||||
validExt = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !validExt {
|
||||
return "", fmt.Errorf("invalid file extension: %s", ext)
|
||||
}
|
||||
|
||||
// Additional check: ensure the path doesn't escape intended directories
|
||||
if strings.Count(absPath, "/") > 10 {
|
||||
return "", fmt.Errorf("path too deep: potential security risk")
|
||||
|
@ -381,7 +366,6 @@ func GetCurrentConfig() (*ConfigInfo, error) {
|
|||
var configPath string
|
||||
var configData *NodeConfig
|
||||
var format string = "hjson"
|
||||
var writable bool = false
|
||||
|
||||
// Use current config if available, otherwise try to read from default location
|
||||
if currentConfigPath != "" && currentConfigData != nil {
|
||||
|
@ -402,72 +386,33 @@ func GetCurrentConfig() (*ConfigInfo, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid default config path: %v", err)
|
||||
}
|
||||
configPath = validatedDefaultPath
|
||||
|
||||
// Try to read existing config file
|
||||
if _, err := os.Stat(configPath); err == nil { // Path already validated above
|
||||
data, err := os.ReadFile(configPath) // Path already validated above
|
||||
if err == nil {
|
||||
cfg := GenerateConfig()
|
||||
if err := hjson.Unmarshal(data, cfg); err == nil {
|
||||
configData = cfg
|
||||
// Detect format
|
||||
var jsonTest interface{}
|
||||
if json.Unmarshal(data, &jsonTest) == nil {
|
||||
format = "json"
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("failed to parse config file: %v", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No config file exists, use default
|
||||
configData = GenerateConfig()
|
||||
}
|
||||
configPath = validatedDefaultPath
|
||||
configData = GenerateConfig()
|
||||
}
|
||||
|
||||
// Detect format from file if path is known
|
||||
if configPath != "" {
|
||||
// Config path is already validated at this point
|
||||
if _, err := os.Stat(configPath); err == nil { // Path already validated above
|
||||
data, err := os.ReadFile(configPath) // Path already validated above
|
||||
if err == nil {
|
||||
// Try to read existing config file
|
||||
if _, err := os.Stat(configPath); err == nil { // Path already validated above
|
||||
data, err := os.ReadFile(configPath) // Path already validated above
|
||||
if err == nil {
|
||||
cfg := GenerateConfig()
|
||||
if err := hjson.Unmarshal(data, cfg); err == nil {
|
||||
configData = cfg
|
||||
// Detect format
|
||||
var jsonTest interface{}
|
||||
if json.Unmarshal(data, &jsonTest) == nil {
|
||||
format = "json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if writable
|
||||
if configPath != "" {
|
||||
// Config path is already validated at this point
|
||||
if _, err := os.Stat(configPath); err == nil { // Path already validated above
|
||||
// File exists, check if writable
|
||||
if file, err := os.OpenFile(configPath, os.O_WRONLY, 0); err == nil { // Path already validated above
|
||||
writable = true
|
||||
file.Close()
|
||||
}
|
||||
} else {
|
||||
// File doesn't exist, check if directory is writable
|
||||
dir := filepath.Clean(filepath.Dir(configPath))
|
||||
if stat, err := os.Stat(dir); err == nil && stat.IsDir() {
|
||||
testFile := filepath.Join(dir, ".yggdrasil_write_test")
|
||||
if file, err := os.Create(testFile); err == nil {
|
||||
file.Close()
|
||||
os.Remove(testFile)
|
||||
writable = true
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("failed to parse config file: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &ConfigInfo{
|
||||
Path: configPath,
|
||||
Format: format,
|
||||
Data: configData,
|
||||
Writable: writable,
|
||||
Path: configPath,
|
||||
Format: format,
|
||||
Data: configData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -516,6 +461,7 @@ func SaveConfig(configData interface{}, configPath, format string) error {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if targetFormat == "" {
|
||||
targetFormat = "hjson"
|
||||
}
|
||||
|
|
|
@ -388,7 +388,6 @@ type ConfigResponse struct {
|
|||
ConfigPath string `json:"config_path"`
|
||||
ConfigFormat string `json:"config_format"`
|
||||
ConfigJSON string `json:"config_json"`
|
||||
IsWritable bool `json:"is_writable"`
|
||||
}
|
||||
|
||||
type ConfigSetRequest struct {
|
||||
|
@ -432,7 +431,6 @@ func (w *WebUIServer) getConfigHandler(rw http.ResponseWriter, r *http.Request)
|
|||
ConfigPath: configInfo.Path,
|
||||
ConfigFormat: configInfo.Format,
|
||||
ConfigJSON: string(configBytes),
|
||||
IsWritable: configInfo.Writable,
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
|
|
@ -30,8 +30,7 @@ async function loadConfiguration() {
|
|||
currentConfigJSON = data.config_json;
|
||||
configMeta = {
|
||||
path: data.config_path,
|
||||
format: data.config_format,
|
||||
isWritable: data.is_writable
|
||||
format: data.config_format
|
||||
};
|
||||
|
||||
renderConfigEditor();
|
||||
|
@ -54,9 +53,6 @@ function renderConfigEditor() {
|
|||
<div class="config-meta">
|
||||
<span class="config-path" title="${configMeta.path}">${configMeta.path}</span>
|
||||
<span class="config-format ${configMeta.format}">${configMeta.format.toUpperCase()}</span>
|
||||
<span class="config-status ${configMeta.isWritable ? 'writable' : 'readonly'}">
|
||||
${configMeta.isWritable ? '✏️ <span data-key="editable">Редактируемый</span>' : '🔒 <span data-key="readonly">Только чтение</span>'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -76,14 +72,12 @@ function renderConfigEditor() {
|
|||
<div onclick="validateJSON()" class="action-btn">
|
||||
<span data-key="validate">Проверить</span>
|
||||
</div>
|
||||
${configMeta.isWritable ? `
|
||||
<div onclick="saveConfiguration()" class="action-btn">
|
||||
<span data-key="save_config">Сохранить</span>
|
||||
</div>
|
||||
<div onclick="saveAndRestartConfiguration()" class="action-btn">
|
||||
<span data-key="save_and_restart">Сохранить и перезапустить</span>
|
||||
</div>
|
||||
` : ''}
|
||||
<div onclick="saveConfiguration()" class="action-btn">
|
||||
<span data-key="save_config">Сохранить</span>
|
||||
</div>
|
||||
<div onclick="saveAndRestartConfiguration()" class="action-btn">
|
||||
<span data-key="save_and_restart">Сохранить и перезапустить</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -93,7 +87,6 @@ function renderConfigEditor() {
|
|||
id="config-json-textarea"
|
||||
class="json-editor"
|
||||
spellcheck="false"
|
||||
${configMeta.isWritable ? '' : 'readonly'}
|
||||
placeholder="Загрузка конфигурации..."
|
||||
oninput="onConfigChange()"
|
||||
onscroll="syncLineNumbers()"
|
||||
|
|
|
@ -1542,9 +1542,6 @@ button[onclick="copyNodeKey()"]:hover {
|
|||
}
|
||||
|
||||
.config-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 30px;
|
||||
padding: 20px;
|
||||
background: var(--bg-info-card);
|
||||
|
@ -1564,13 +1561,6 @@ button[onclick="copyNodeKey()"]:hover {
|
|||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.config-meta {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.config-path {
|
||||
font-family: 'Courier New', monospace;
|
||||
background: var(--bg-nav-item);
|
||||
|
@ -1602,25 +1592,6 @@ button[onclick="copyNodeKey()"]:hover {
|
|||
color: #7b1fa2;
|
||||
}
|
||||
|
||||
.config-status {
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.8em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.config-status.writable {
|
||||
background: var(--bg-success);
|
||||
color: var(--text-success);
|
||||
}
|
||||
|
||||
.config-status.readonly {
|
||||
background: var(--bg-warning);
|
||||
color: var(--text-warning);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Configuration Groups */
|
||||
.config-groups {
|
||||
display: flex;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue