mirror of https://github.com/oupson/FooTerm.git
Store server in db, password in secret and display server list
This commit is contained in:
parent
7359a03f90
commit
d7b4940608
|
@ -12,7 +12,8 @@
|
|||
"--share=ipc",
|
||||
"--socket=fallback-x11",
|
||||
"--device=dri",
|
||||
"--socket=wayland"
|
||||
"--socket=wayland",
|
||||
"--talk-name=org.freedesktop.secrets"
|
||||
],
|
||||
"build-options" : {
|
||||
"append-path" : "/usr/lib/sdk/vala/bin",
|
||||
|
|
|
@ -20,12 +20,14 @@
|
|||
|
||||
namespace Footerm.Model {
|
||||
public class Server {
|
||||
public int? id;
|
||||
public string name;
|
||||
public string hostname;
|
||||
public ushort port;
|
||||
public string username;
|
||||
|
||||
public Server(string name, string hostname, ushort port, string username) {
|
||||
public Server(int? id, string name, string hostname, ushort port, string username) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.hostname = hostname;
|
||||
this.port = port;
|
||||
|
|
|
@ -33,27 +33,38 @@ namespace Footerm {
|
|||
[GtkChild]
|
||||
private unowned Gtk.Button newpane_add_button;
|
||||
|
||||
public signal void on_server_selected(Footerm.Model.Server server);
|
||||
public signal void on_server_selected (Footerm.Model.Server server);
|
||||
|
||||
construct {
|
||||
this.new_server.on_new_server.connect((s) => {
|
||||
this.newpane_stack.set_visible_child(server_list.get_parent());
|
||||
var action_row = new Adw.ActionRow();
|
||||
action_row.set_title(s.hostname);
|
||||
action_row.set_activatable(true);
|
||||
action_row.activated.connect(() => {
|
||||
this.on_server_selected(s);
|
||||
this.new_server.on_new_server.connect ((s) => {
|
||||
this.newpane_stack.set_visible_child (server_list.get_parent ());
|
||||
var action_row = new Adw.ActionRow ();
|
||||
action_row.set_title (s.hostname);
|
||||
action_row.set_activatable (true);
|
||||
action_row.activated.connect (() => {
|
||||
this.on_server_selected (s);
|
||||
});
|
||||
server_list.add(action_row);
|
||||
server_list.add (action_row);
|
||||
});
|
||||
this.newpane_add_button.clicked.connect (() => {
|
||||
this.newpane_stack.set_visible_child(new_server.get_parent());
|
||||
this.newpane_stack.set_visible_child (new_server.get_parent ());
|
||||
});
|
||||
|
||||
try {
|
||||
var config = Footerm.Services.Config.get_instance();
|
||||
var config = Footerm.Services.Config.get_instance ();
|
||||
|
||||
var stored_server_list = config.get_server_list ();
|
||||
foreach (var server in stored_server_list) {
|
||||
var action_row = new Adw.ActionRow ();
|
||||
action_row.set_title (server.name);
|
||||
action_row.set_activatable (true);
|
||||
action_row.activated.connect (() => {
|
||||
this.on_server_selected (server);
|
||||
});
|
||||
server_list.add (action_row);
|
||||
}
|
||||
} catch (Error e) {
|
||||
GLib.warning("Failed to read server list : %s", e.message);
|
||||
GLib.warning ("Failed to read server list : %s", e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<child>
|
||||
<object class="AdwEntryRow" id="name_entry">
|
||||
<property name="title" translatable="yes">Name</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwEntryRow" id="hostname_entry">
|
||||
<property name="title" translatable="yes">Hostname</property>
|
||||
|
|
|
@ -22,6 +22,8 @@ namespace Footerm {
|
|||
[GtkTemplate(ui = "/fr/oupson/FooTerm/newserver.ui")]
|
||||
public class NewServer : Gtk.Box {
|
||||
public signal void on_new_server(Footerm.Model.Server server);
|
||||
[GtkChild]
|
||||
private unowned Adw.EntryRow name_entry;
|
||||
|
||||
[GtkChild]
|
||||
private unowned Adw.EntryRow hostname_entry;
|
||||
|
@ -42,7 +44,8 @@ namespace Footerm {
|
|||
add_server_button.clicked.connect(this.on_add_button_clicked);
|
||||
}
|
||||
|
||||
private void on_add_button_clicked() {
|
||||
private async void on_add_button_clicked() {
|
||||
var name = this.name_entry.get_text();
|
||||
var hostname = this.hostname_entry.get_text();
|
||||
var port = int.parse(this.port_entry.get_text());
|
||||
var username = this.username_entry.get_text();
|
||||
|
@ -52,7 +55,11 @@ namespace Footerm {
|
|||
// Port is invalid
|
||||
}
|
||||
|
||||
// this.on_new_server(new Footerm.Model.Server(hostname, (ushort)port, username, password));
|
||||
var server = new Footerm.Model.Server(null, name, hostname, (ushort)port, username);
|
||||
var config_service = Footerm.Services.Config.get_instance();
|
||||
yield config_service.save_server(server, password);
|
||||
|
||||
this.on_new_server(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ namespace Footerm.Services {
|
|||
public List<Footerm.Model.Server> get_server_list() throws ConfigError {
|
||||
List<Footerm.Model.Server> list = new List<Footerm.Model.Server> ();
|
||||
|
||||
var stm_str = "SELECT (serverId, serverName, serverHostName, serverPort) FROM SERVER";
|
||||
var stm_str = "SELECT serverId, serverName, serverHostName, serverPort, serverUsername FROM SERVER;";
|
||||
Sqlite.Statement stm;
|
||||
var ec = this.db.prepare_v2(stm_str, stm_str.length, out stm);
|
||||
if (ec != Sqlite.OK) {
|
||||
|
@ -119,10 +119,48 @@ namespace Footerm.Services {
|
|||
}
|
||||
|
||||
while (stm.step() == Sqlite.ROW) {
|
||||
list.append(new Footerm.Model.Server(stm.column_text(0), stm.column_text(1), (ushort) stm.column_int(2), stm.column_text(3)));
|
||||
list.append(new Footerm.Model.Server(stm.column_int(0), stm.column_text(1), stm.column_text(2), (ushort) stm.column_int(3), stm.column_text(4)));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public async void save_server(Footerm.Model.Server server, string password) throws ConfigError, SecretError, Error {
|
||||
var secrets = Secrets.get_instance();
|
||||
yield secrets.store_password(server, password);
|
||||
|
||||
var stm_str = "INSERT INTO SERVER (serverName, serverHostName, serverPort, serverUsername, serverAuthentificationType) VALUES(?, ?, ?, ?, 'password')";
|
||||
Sqlite.Statement stm;
|
||||
var ec = this.db.prepare_v2(stm_str, stm_str.length, out stm);
|
||||
if (ec != Sqlite.OK) {
|
||||
throw new ConfigError.DATABASE(@"Can't insert server: $(db.errcode ()): $(db.errmsg ())");
|
||||
}
|
||||
|
||||
ec = stm.bind_text(1, server.name);
|
||||
if (ec != Sqlite.OK) {
|
||||
throw new ConfigError.DATABASE(@"Can't insert server: $(db.errcode ()): $(db.errmsg ())");
|
||||
}
|
||||
ec = stm.bind_text(2, server.hostname);
|
||||
if (ec != Sqlite.OK) {
|
||||
throw new ConfigError.DATABASE(@"Can't insert server: $(db.errcode ()): $(db.errmsg ())");
|
||||
}
|
||||
ec = stm.bind_int(3, server.port);
|
||||
if (ec != Sqlite.OK) {
|
||||
throw new ConfigError.DATABASE(@"Can't insert server: $(db.errcode ()): $(db.errmsg ())");
|
||||
}
|
||||
ec = stm.bind_text(4, server.username);
|
||||
if (ec != Sqlite.OK) {
|
||||
throw new ConfigError.DATABASE(@"Can't insert server: $(db.errcode ()): $(db.errmsg ())");
|
||||
}
|
||||
|
||||
ec = stm.step();
|
||||
stm.reset();
|
||||
|
||||
if (ec != Sqlite.DONE) {
|
||||
throw new ConfigError.DATABASE(@"Can't insert server: $(db.errcode ()): $(db.errmsg ())");
|
||||
}
|
||||
|
||||
server.id = (int)this.db.last_insert_rowid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/* Secrets.vala
|
||||
*
|
||||
* Copyright 2023 oupson
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Footerm.Services {
|
||||
public errordomain SecretError {
|
||||
FAILED_TO_STORE
|
||||
}
|
||||
|
||||
public class Secrets {
|
||||
private static Secrets instance = null;
|
||||
|
||||
public static Secrets get_instance() {
|
||||
if (Secrets.instance == null) {
|
||||
Secrets.instance = new Secrets();
|
||||
}
|
||||
return Secrets.instance;
|
||||
}
|
||||
|
||||
private Secret.Schema password_schema;
|
||||
|
||||
private Secrets() {
|
||||
this.password_schema = new Secret.Schema("fr.oupson.FooTerm.Password", Secret.SchemaFlags.NONE,
|
||||
"hostname", Secret.SchemaAttributeType.STRING,
|
||||
"port", Secret.SchemaAttributeType.INTEGER,
|
||||
"username", Secret.SchemaAttributeType.STRING);
|
||||
}
|
||||
|
||||
public async void store_password(Footerm.Model.Server server, string password) throws SecretError, Error {
|
||||
var attributes = new GLib.HashTable<string, string> (str_hash, str_equal);
|
||||
attributes["hostname"] = server.hostname;
|
||||
attributes["port"] = server.port.to_string();
|
||||
attributes["username"] = server.username;
|
||||
|
||||
var res = yield Secret.password_storev(this.password_schema, attributes, Secret.COLLECTION_DEFAULT, @"$(server.username)@$(server.hostname):$(server.port)", password, null);
|
||||
|
||||
if (!res) {
|
||||
throw new SecretError.FAILED_TO_STORE("Failed to store the password");
|
||||
}
|
||||
debug("Password is stored");
|
||||
}
|
||||
|
||||
public async string get_password(Footerm.Model.Server server) throws Error {
|
||||
var attributes = new GLib.HashTable<string, string> (str_hash, str_equal);
|
||||
attributes["hostname"] = server.hostname;
|
||||
attributes["port"] = server.port.to_string();
|
||||
attributes["username"] = server.username;
|
||||
|
||||
return yield Secret.password_lookupv(this.password_schema, attributes, null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
footerm_sources += files(
|
||||
'Config.vala'
|
||||
'Config.vala',
|
||||
'Secrets.vala'
|
||||
)
|
|
@ -34,7 +34,13 @@ namespace Footerm {
|
|||
public TerminalPane(Footerm.Model.Server server) {
|
||||
this.server = server;
|
||||
this.terminal.set_enable_sixel(true);
|
||||
this.connect_to_server();
|
||||
this.connect_to_server.begin((obj, res) => {
|
||||
try {
|
||||
this.connect_to_server.end(res);
|
||||
} catch (Error e) {
|
||||
warning("Failed to connect to the server : %s", e.message);
|
||||
}
|
||||
});
|
||||
this.terminal.char_size_changed.connect(() => {
|
||||
int rows = 0;
|
||||
int columns = 0;
|
||||
|
@ -51,7 +57,7 @@ namespace Footerm {
|
|||
// stdout.printf("all done!\n");)
|
||||
}
|
||||
|
||||
private void connect_to_server() throws GLib.IOError, GLib.Error {
|
||||
private async void connect_to_server() throws GLib.IOError, GLib.Error {
|
||||
var addrs = new NetworkAddress(this.server.hostname, this.server.port);
|
||||
var addr = addrs.enumerate().next();
|
||||
this.socket = new Socket(addr.get_family(), SocketType.STREAM, SocketProtocol.TCP);
|
||||
|
@ -73,7 +79,10 @@ namespace Footerm {
|
|||
stdout.printf("\n");
|
||||
|
||||
// TODO QUERY PASSWORD FROM libsecret
|
||||
if (session.auth_password(this.server.username, null) != SSH2.Error.NONE) {
|
||||
var secrets = Footerm.Services.Secrets.get_instance();
|
||||
var password = yield secrets.get_password(this.server);
|
||||
|
||||
if (session.auth_password(this.server.username, password) != SSH2.Error.NONE) {
|
||||
stdout.printf("\tAuthentication by password failed!\n");
|
||||
session.disconnect("Normal Shutdown, Thank you for playing");
|
||||
session = null;
|
||||
|
|
|
@ -29,14 +29,14 @@ namespace Footerm {
|
|||
}
|
||||
|
||||
construct {
|
||||
var action = new SimpleAction("new_tab", null);
|
||||
var action = new SimpleAction ("new_tab", null);
|
||||
action.activate.connect (() => {
|
||||
var a = view.append (new Footerm.Pane());
|
||||
var a = view.append (new Footerm.Pane ());
|
||||
a.set_title ("New Pane");
|
||||
view.set_selected_page (a);
|
||||
});
|
||||
this.add_action (action);
|
||||
var a = view.append (new Footerm.Pane());
|
||||
var a = view.append (new Footerm.Pane ());
|
||||
a.set_title ("New Pane");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue