summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hscript/user.cc24
-rw-r--r--tests/fixtures/0098-usericon-basic.installfile7
-rw-r--r--tests/fixtures/0099-usericon-without-icon.installfile7
-rw-r--r--tests/fixtures/0100-usericon-unknown-name.installfile8
-rw-r--r--tests/fixtures/0101-usericon-duplicate.installfile8
-rw-r--r--tests/fixtures/0102-usericon-protocols.installfile15
-rw-r--r--tests/fixtures/0103-usericon-gopher.installfile7
-rw-r--r--tests/spec/validator.rb39
-rw-r--r--util/net.hh36
9 files changed, 149 insertions, 2 deletions
diff --git a/hscript/user.cc b/hscript/user.cc
index 6081f55..04258e4 100644
--- a/hscript/user.cc
+++ b/hscript/user.cc
@@ -17,6 +17,7 @@
#include <sstream>
#include <time.h>
#include "user.hh"
+#include "util/net.hh"
#include "util/output.hh"
using namespace Horizon::Keys;
@@ -264,11 +265,30 @@ bool UserPassphrase::execute(ScriptOptions) const {
Key *UserIcon::parseFromData(const std::string &data, int lineno, int *errors,
int *warnings) {
- return nullptr;
+ /* REQ: Runner.Validate.usericon.Validity */
+ const std::string::size_type sep = data.find_first_of(' ');
+ if(sep == std::string::npos || data.length() == sep + 1) {
+ if(errors) *errors += 1;
+ output_error("installfile:" + std::to_string(lineno),
+ "usericon: icon is required",
+ "expected format is: usericon [username] [path|url]");
+ return nullptr;
+ }
+
+ std::string icon_path = data.substr(sep + 1);
+ if(icon_path[0] != '/' && !is_valid_url(icon_path)) {
+ if(errors) *errors += 1;
+ output_error("installfile:" + std::to_string(lineno),
+ "usericon: path must be absolute path or valid URL");
+ return nullptr;
+ }
+
+ return new UserIcon(lineno, data.substr(0, sep), icon_path);
}
bool UserIcon::validate(ScriptOptions) const {
- return false;
+ /* TODO XXX: ensure URL is accessible */
+ return true;
}
bool UserIcon::execute(ScriptOptions) const {
diff --git a/tests/fixtures/0098-usericon-basic.installfile b/tests/fixtures/0098-usericon-basic.installfile
new file mode 100644
index 0000000..8abb1a7
--- /dev/null
+++ b/tests/fixtures/0098-usericon-basic.installfile
@@ -0,0 +1,7 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+username awilfox
+usericon awilfox /usr/share/user-manager/avatars/circles/Cat.png
diff --git a/tests/fixtures/0099-usericon-without-icon.installfile b/tests/fixtures/0099-usericon-without-icon.installfile
new file mode 100644
index 0000000..bdedf34
--- /dev/null
+++ b/tests/fixtures/0099-usericon-without-icon.installfile
@@ -0,0 +1,7 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+username awilfox
+usericon awilfox
diff --git a/tests/fixtures/0100-usericon-unknown-name.installfile b/tests/fixtures/0100-usericon-unknown-name.installfile
new file mode 100644
index 0000000..047b8eb
--- /dev/null
+++ b/tests/fixtures/0100-usericon-unknown-name.installfile
@@ -0,0 +1,8 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+username awilfox
+# Intentional misspelling
+usericon awilcox /usr/share/user-manager/avatars/circles/Cat.png
diff --git a/tests/fixtures/0101-usericon-duplicate.installfile b/tests/fixtures/0101-usericon-duplicate.installfile
new file mode 100644
index 0000000..b572891
--- /dev/null
+++ b/tests/fixtures/0101-usericon-duplicate.installfile
@@ -0,0 +1,8 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+username awilfox
+usericon awilfox /usr/share/user-manager/avatars/circles/Cat.png
+usericon awilfox /usr/share/user-manager/avatars/classic/TV.png
diff --git a/tests/fixtures/0102-usericon-protocols.installfile b/tests/fixtures/0102-usericon-protocols.installfile
new file mode 100644
index 0000000..246dc94
--- /dev/null
+++ b/tests/fixtures/0102-usericon-protocols.installfile
@@ -0,0 +1,15 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+username chris
+usericon chris http://www.adelielinux.org/
+username kayla
+usericon kayla HTTPS://www.adelielinux.org/
+username meg
+usericon meg /usr/share/user-manager/avatars/circles/Cat.png
+username steph
+usericon steph tftp://192.168.1.1/avatar
+username amanda
+usericon amanda SmB://stuff:pw@10.4.1.1/c$/mypicture
diff --git a/tests/fixtures/0103-usericon-gopher.installfile b/tests/fixtures/0103-usericon-gopher.installfile
new file mode 100644
index 0000000..4a901b5
--- /dev/null
+++ b/tests/fixtures/0103-usericon-gopher.installfile
@@ -0,0 +1,7 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+username awilfox
+usericon awilfox gopher://bbs.sick.bike/l/upload/b/13.jpe
diff --git a/tests/spec/validator.rb b/tests/spec/validator.rb
index 76f1c6f..e43e5ed 100644
--- a/tests/spec/validator.rb
+++ b/tests/spec/validator.rb
@@ -612,6 +612,45 @@ RSpec.describe 'HorizonScript validation', :type => :aruba do
expect(last_command_started).to have_output(/warning: .*passphrase/)
end
end
+ context "'usericon'" do
+ # Runner.Validate.usericon.
+ it "succeeds with a valid icon/account pair" do
+ use_fixture '0098-usericon-basic.installfile'
+ run_validate
+ expect(last_command_started).to have_output(PARSER_SUCCESS)
+ expect(last_command_started).to have_output(VALIDATOR_SUCCESS)
+ end
+ # Runner.Validate.usericon.Validity.
+ it "requires a path to be provided" do
+ use_fixture '0099-usericon-without-icon.installfile'
+ run_validate
+ expect(last_command_started).to have_output(/error: .*usericon.*required/)
+ end
+ # Runner.Validate.usericon.Name.
+ it "fails with a username that wasn't given" do
+ use_fixture '0100-usericon-unknown-name.installfile'
+ run_validate
+ expect(last_command_started).to have_output(/error: .*usericon.*name/)
+ end
+ # Runner.Validate.usericon.Unique.
+ it "fails with multiple icons associated with a single account" do
+ use_fixture '0101-usericon-duplicate.installfile'
+ run_validate
+ expect(last_command_started).to have_output(/error: .*duplicate.*usericon/)
+ end
+ # Runner.Validate.usericon.ValidPath.
+ it "succeeds with all supported protocols" do
+ use_fixture '0102-usericon-protocols.installfile'
+ run_validate
+ expect(last_command_started).to have_output(PARSER_SUCCESS)
+ expect(last_command_started).to have_output(VALIDATOR_SUCCESS)
+ end
+ it "fails with an unsupported protocol" do
+ use_fixture '0103-usericon-gopher.installfile'
+ run_validate
+ expect(last_command_started).to have_output(/error: .*usericon.*URL/)
+ end
+ end
end
context "package specifications" do
# no requirements for these, but I think obvious.
diff --git a/util/net.hh b/util/net.hh
new file mode 100644
index 0000000..89e5303
--- /dev/null
+++ b/util/net.hh
@@ -0,0 +1,36 @@
+/*
+ * net.hh - Miscellaneous networking routines
+ * util, the utility library for
+ * Project Horizon
+ *
+ * Copyright (c) 2019 Adélie Linux and contributors. All rights reserved.
+ * This code is licensed under the AGPL 3.0 license, as noted in the
+ * LICENSE-code file in the root directory of this repository.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+#ifndef __HORIZON_NET_HH_
+#define __HORIZON_NET_HH_
+
+#include <algorithm>
+#include <string>
+
+/*! Determine if a string starts with a valid, supported protocol
+ * @param url The URL.
+ * @returns true if +url+ is a URL for a supported protocol, false otherwise.
+ */
+static bool is_valid_url(const std::string &url) {
+ std::string::size_type colon = url.find("://");
+ /* If there's no ://, it's definitely not a URL */
+ if(colon == std::string::npos) return false;
+ std::string proto = url.substr(0, colon);
+ std::transform(proto.cbegin(), proto.cend(), proto.begin(), ::tolower);
+ if(proto == "http" || proto == "https" || proto == "tftp" || proto == "smb"
+ || proto == "cifs") {
+ return true;
+ }
+ return false;
+}
+
+#endif /* !__HORIZON_NET_HH */