Repository: gobackup/gobackup

Issue:
[BUG] The request to `/api/log` was missing cookies
# Overview
I have authelia as the entry component in my system, but when I checked, the request sent to `/api/log` was redirected by authelia due to the lack of authentication cookies, so the request failed and there was only an error but no log in the Web UI.

# Solution
~~When sending requests to the API endpoint, include the cookies.~~

~~Seems like it's a bug from upstream https://github.com/mozilla-frontend-infra/react-lazylog~~
~~Unfortunately, this repository is now public archived. T_T~~

It's not a bug.
To fix it, adding `fetchOptions={{ credentials: 'include' }}` to `<LasyLog />` can solve it.

Discussion:

Solution patch:
diff --git a/README.md b/README.md
index 4a36803..a838b37 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,7 @@ https://gobackup.github.io
 - InfluxDB
 - MariaDB
 - etcd
+- Firebird
 
 ### Storages
 
diff --git a/database/base.go b/database/base.go
index 85096a1..5809ccf 100644
--- a/database/base.go
+++ b/database/base.go
@@ -83,6 +83,8 @@ func runModel(model config.ModelConfig, dbConfig config.SubConfig) (err error) {
 		db = &InfluxDB2{Base: base}
 	case "etcd":
 		db = &Etcd{Base: base}
+	case "firebird":
+		db = &Firebird{Base: base}
 	default:
 		logger.Warn(fmt.Errorf("model: %s databases.%s config `type: %s`, but is not implement", model.Name, dbConfig.Name, dbConfig.Type))
 		return
diff --git a/database/firebird.go b/database/firebird.go
new file mode 100644
index 0000000..be04d2a
--- /dev/null
+++ b/database/firebird.go
@@ -0,0 +1,101 @@
+package database
+
+import (
+	"fmt"
+	"path"
+	"strings"
+
+	"github.com/gobackup/gobackup/helper"
+	"github.com/gobackup/gobackup/logger"
+)
+
+// Firebird database
+//
+// With gbak utility : https://www.firebirdsql.org/file/documentation/html/en/firebirddocs/gbak/firebird-gbak.html
+//
+// type: firebird
+// host: 127.0.0.1
+// port: 3050
+// database:
+// username:
+// password:
+// role:
+type Firebird struct {
+	Base
+	host                   string
+	port                   string
+	database               string
+	username               string
+	password               string
+	role 				   string
+	args                   string
+	_dumpFilePath	 	   string
+}
+
+func (db *Firebird) init() (err error) {
+	viper := db.viper
+	viper.SetDefault("host", "127.0.0.1")
+	viper.SetDefault("port", 3050)
+	viper.SetDefault("username", "sysdba")
+	viper.SetDefault("password", "masterkey")
+
+	db.host = viper.GetString("host")
+	db.port = viper.GetString("port")
+	db.database = viper.GetString("database")
+	db.username = viper.GetString("username")
+	db.role = viper.GetString("role")
+	db.password = viper.GetString("password")
+	db.args = viper.GetString("args")
+
+	if len(db.database) == 0 {
+		return fmt.Errorf("Firebird database config is required")
+	}
+
+	return nil
+}
+
+func (db *Firebird) build() string {
+	// gbak command
+	var gbakArgs []string
+	
+	gbakArgs = append(gbakArgs, "-b")
+
+	if len(db.username) > 0 {
+		gbakArgs = append(gbakArgs, "-user "+db.username)
+	}
+	if len(db.password) > 0 {
+		gbakArgs = append(gbakArgs, "-pass "+db.password)
+	}
+	if len(db.role) > 0 {
+		gbakArgs = append(gbakArgs, "-role "+db.role)
+	}
+
+	var dbString string
+	if (len(db.host) > 0 && len(db.port) > 0) {
+		dbString = db.host+"/"+db.port+":"
+	}
+	
+	dbString = dbString + db.database
+	db._dumpFilePath = path.Join(
+		db.dumpPath, 
+		strings.TrimSuffix(path.Base(db.database), path.Ext(db.database)) + ".fbk",
+	)
+
+	gbakArgs = append(gbakArgs, dbString)
+	gbakArgs = append(gbakArgs, db._dumpFilePath)
+
+	return "gbak " + strings.Join(gbakArgs, " ")
+}
+
+func (db *Firebird) perform() error {
+	logger := logger.Tag("Firebird")
+
+	logger.Info("-> Dumping Firebird...")
+
+	_, err := helper.Exec(db.build())
+	if err != nil {
+		return err
+	}
+	logger.Info("dump path:", db.dumpPath)
+	return nil
+}
diff --git a/web/src/App.tsx b/web/src/App.tsx
index aaf7328..9710644 100644
--- a/web/src/App.tsx
+++ b/web/src/App.tsx
@@ -25,6 +25,7 @@ const LogView = () => {
             stream
             follow={follow}
             onScroll={onScroll}
+            fetchOptions={{ credentials: 'include' }}
           />
         )}
       />



Test patch:
diff --git a/database/firebird_test.go b/database/firebird_test.go
new file mode 100644
index 0000000..875e644
--- /dev/null
+++ b/database/firebird_test.go
@@ -0,0 +1,99 @@
+package database
+
+import (
+	"testing"
+
+	"github.com/gobackup/gobackup/config"
+	"github.com/longbridgeapp/assert"
+	"github.com/spf13/viper"
+)
+
+func TestFirebirdSQL_init(t *testing.T) {
+	viper := viper.New()
+	viper.Set("host", "1.2.3.4")
+	viper.Set("port", "3051")
+	viper.Set("database", "my_db")
+	viper.Set("username", "user1")
+	viper.Set("role", "role1")
+	viper.Set("password", "pass1")
+
+	base := newBase(
+		config.ModelConfig{
+			DumpPath: "/data/backups/",
+		},
+		// Creating a new base object.
+		config.SubConfig{
+			Type:  "firebird",
+			Name:  "firebird1",
+			Viper: viper,
+		},
+	)
+
+	db := &Firebird{
+		Base: base,
+	}
+
+	err := db.init()
+	assert.NoError(t, err)
+
+	assert.Equal(t, db.build(), "gbak -b -user user1 -pass pass1 -role role1 1.2.3.4/3051:my_db /data/backups/firebird/firebird1/my_db.fbk")
+}
+
+func TestFirebirdSQL_withDatabasePath(t *testing.T) {
+	viper := viper.New()
+	viper.Set("host", "1.2.3.4")
+	viper.Set("port", "3050")
+	viper.Set("database", "/var/databases/test.fdb")
+	viper.Set("username", "user1")
+	viper.Set("role", "role1")
+	viper.Set("password", "pass1")
+
+	base := newBase(
+		config.ModelConfig{
+			DumpPath: "/data/backups/",
+		},
+		// Creating a new base object.
+		config.SubConfig{
+			Type:  "firebird",
+			Name:  "firebird1",
+			Viper: viper,
+		},
+	)
+
+	db := &Firebird{
+		Base: base,
+	}
+
+	err := db.init()
+	assert.NoError(t, err)
+
+	assert.Equal(t, db.build(), "gbak -b -user user1 -pass pass1 -role role1 1.2.3.4/3050:/var/databases/test.fdb /data/backups/firebird/firebird1/test.fbk")
+}
+
+func TestFirebirdSQL_withoutHost(t *testing.T) {
+	viper := viper.New()
+	viper.Set("database", "DB_ALIAS")
+	viper.Set("username", "user1")
+	viper.Set("password", "pass1")
+
+	base := newBase(
+		config.ModelConfig{
+			DumpPath: "/data/backups/",
+		},
+		// Creating a new base object.
+		config.SubConfig{
+			Type:  "firebird",
+			Name:  "firebird1",
+			Viper: viper,
+		},
+	)
+
+	db := &Firebird{
+		Base: base,
+	}
+
+	err := db.init()
+	assert.NoError(t, err)
+
+	assert.Equal(t, db.build(), "gbak -b -user user1 -pass pass1 127.0.0.1/3050:DB_ALIAS /data/backups/firebird/firebird1/DB_ALIAS.fbk")
+}