Skip to content

Commit 884e764

Browse files
committed
Refactored project with .net core based controller.
1 parent fa1cb7d commit 884e764

37 files changed

+915
-724
lines changed

.dockerignore

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
**/.classpath
2+
**/.dockerignore
3+
**/.env
4+
**/.git
5+
**/.gitignore
6+
**/.project
7+
**/.settings
8+
**/.toolstarget
9+
**/.vs
10+
**/.vscode
11+
**/*.*proj.user
12+
**/*.dbmdl
13+
**/*.jfm
14+
**/azds.yaml
15+
**/bin
16+
**/charts
17+
**/docker-compose*
18+
**/Dockerfile*
19+
**/node_modules
20+
**/npm-debug.log
21+
**/obj
22+
**/secrets.dev.yaml
23+
**/values.dev.yaml
24+
LICENSE
25+
README.md
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace ES.SFTP.Host.Business.Configuration
2+
{
3+
public class ChrootDefinition
4+
{
5+
public string Directory { get; set; }
6+
public string StartPath { get; set; }
7+
}
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Collections.Generic;
2+
3+
namespace ES.SFTP.Host.Business.Configuration
4+
{
5+
public class GlobalConfiguration
6+
{
7+
public string HomeDirectory { get; set; }
8+
public ChrootDefinition Chroot { get; set; }
9+
public List<string> Directories { get; set; } = new List<string>();
10+
}
11+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System.Collections.Generic;
2+
3+
namespace ES.SFTP.Host.Business.Configuration
4+
{
5+
public class SftpConfiguration
6+
{
7+
public GlobalConfiguration Global { get; set; }
8+
public List<UserDefinition> Users { get; set; }
9+
}
10+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System.Collections.Generic;
2+
3+
namespace ES.SFTP.Host.Business.Configuration
4+
{
5+
public class UserDefinition
6+
{
7+
public string Username { get; set; }
8+
public string Password { get; set; }
9+
public bool PasswordIsEncrypted { get; set; }
10+
public int? UID { get; set; }
11+
public int? GID { get; set; }
12+
public ChrootDefinition Chroot { get; set; }
13+
public List<string> Directories { get; set; } = new List<string>();
14+
}
15+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace ES.SFTP.Host.Business.Interop
2+
{
3+
public class ProcessRunOutput
4+
{
5+
public string Output { get; set; }
6+
public int ExitCode { get; set; }
7+
}
8+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Text;
4+
using System.Threading.Tasks;
5+
6+
namespace ES.SFTP.Host.Business.Interop
7+
{
8+
public class ProcessUtil
9+
{
10+
public static Task<ProcessRunOutput> QuickRun(string filename, string arguments = null,
11+
bool throwOnError = true)
12+
{
13+
var outputStringBuilder = new StringBuilder();
14+
var process = new Process
15+
{
16+
StartInfo =
17+
{
18+
FileName = filename,
19+
Arguments = arguments ?? string.Empty,
20+
UseShellExecute = false,
21+
RedirectStandardOutput = true,
22+
RedirectStandardError = true,
23+
CreateNoWindow = true
24+
}
25+
};
26+
process.OutputDataReceived += (_, e) => outputStringBuilder.Append(e.Data);
27+
process.ErrorDataReceived += (_, e) => outputStringBuilder.Append(e.Data);
28+
try
29+
{
30+
process.Start();
31+
process.BeginOutputReadLine();
32+
process.BeginErrorReadLine();
33+
process.WaitForExit();
34+
}
35+
catch (Exception)
36+
{
37+
if (throwOnError) throw;
38+
}
39+
40+
var output = outputStringBuilder.ToString();
41+
if (process.ExitCode != 0 && throwOnError)
42+
throw new Exception(
43+
$"Process failed with exit code '{process.ExitCode}.{Environment.NewLine}{output}'");
44+
return Task.FromResult(new ProcessRunOutput
45+
{
46+
ExitCode = process.ExitCode,
47+
Output = output
48+
});
49+
}
50+
}
51+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using ES.SFTP.Host.Business.Interop;
6+
7+
namespace ES.SFTP.Host.Business.Security
8+
{
9+
public class GroupUtil
10+
{
11+
public static async Task<bool> GroupExists(string groupNameOrId)
12+
{
13+
var command = await ProcessUtil.QuickRun("getent", $"group {groupNameOrId}", false);
14+
return command.ExitCode == 0 && !string.IsNullOrWhiteSpace(command.Output);
15+
}
16+
17+
public static async Task GroupCreate(string name, bool force = false, int? groupId = null,
18+
bool nonUniqueGroupId = true)
19+
{
20+
await ProcessUtil.QuickRun("groupadd",
21+
$"{(force ? "-f" : string.Empty)} {(groupId != null ? $"-g {groupId} {(nonUniqueGroupId ? "-o" : string.Empty)}" : string.Empty)} {name}");
22+
}
23+
24+
public static async Task GroupAddUser(string group, string username)
25+
{
26+
await ProcessUtil.QuickRun("usermod", $"-a -G {group} {username}");
27+
}
28+
29+
public static async Task<IReadOnlyList<string>> GroupListUsers(string group)
30+
{
31+
var command = await ProcessUtil.QuickRun("members", group, false);
32+
if (command.ExitCode != 0 && command.ExitCode != 1 && !string.IsNullOrWhiteSpace(command.Output))
33+
throw new Exception($"Get group members command failed with exit code {command.ExitCode} and message:" +
34+
$"{Environment.NewLine}{command.Output}");
35+
return command.Output.Split(' ', StringSplitOptions.RemoveEmptyEntries).OrderBy(s => s).ToList();
36+
}
37+
}
38+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System.Threading.Tasks;
2+
using ES.SFTP.Host.Business.Interop;
3+
4+
namespace ES.SFTP.Host.Business.Security
5+
{
6+
public class UserUtil
7+
{
8+
public static async Task<bool> UserExists(string username)
9+
{
10+
var command = await ProcessUtil.QuickRun("getent", $"passwd {username}", false);
11+
return command.ExitCode == 0 && !string.IsNullOrWhiteSpace(command.Output);
12+
}
13+
14+
public static async Task UserCreate(string username, bool noLoginShell = false)
15+
{
16+
await ProcessUtil.QuickRun("useradd",
17+
$"--comment {username} {(noLoginShell ? "-s /usr/sbin/nologin" : string.Empty)} {username}");
18+
}
19+
20+
public static async Task UserDelete(string username)
21+
{
22+
await ProcessUtil.QuickRun("userdel", username);
23+
}
24+
25+
public static async Task UserSetId(string username, int id, bool nonUnique = true)
26+
{
27+
await ProcessUtil.QuickRun("pkill", $"-U {await UserGetId(username)}", false);
28+
await ProcessUtil.QuickRun("usermod",
29+
$"{(nonUnique ? "--non-unique" : string.Empty)} --uid {id} {username}");
30+
}
31+
32+
public static async Task UserSetPassword(string username, string password, bool passwordIsEncrypted)
33+
{
34+
if (string.IsNullOrEmpty(password))
35+
await ProcessUtil.QuickRun("usermod", $"-p \"*\" {username}");
36+
else
37+
await ProcessUtil.QuickRun("bash",
38+
$"-c \"echo \\\"{username}:{password}\\\" | chpasswd {(passwordIsEncrypted ? "-e" : string.Empty)} \"");
39+
}
40+
41+
public static async Task<int> UserGetId(string username)
42+
{
43+
var command = await ProcessUtil.QuickRun("id", $"-u {username}");
44+
return int.Parse(command.Output);
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)