mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-25 05:56:58 +01:00
Merge pull request #200 from Cyberboss/ConfigACLImpersonation
New static configuration page
This commit is contained in:
@@ -10,13 +10,40 @@ namespace TGCommandLine
|
||||
public ConfigCommand()
|
||||
{
|
||||
Keyword = "config";
|
||||
Children = new Command[] { new ConfigServerDirectoryCommand(), new ConfigDownloadCommand(), new ConfigUploadCommand(), new ConfigListCommand() };
|
||||
Children = new Command[] { new ConfigDeleteCommand(), new ConfigServerDirectoryCommand(), new ConfigDownloadCommand(), new ConfigUploadCommand(), new ConfigListCommand() };
|
||||
}
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Manage settings";
|
||||
}
|
||||
}
|
||||
class ConfigDeleteCommand : Command
|
||||
{
|
||||
public ConfigDeleteCommand()
|
||||
{
|
||||
Keyword = "delete";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
|
||||
protected override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var res = Server.GetComponent<ITGConfig>().DeleteFile(parameters[0], out bool unauthorized);
|
||||
if (res != null)
|
||||
{
|
||||
OutputProc(res);
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
public override string GetArgumentString()
|
||||
{
|
||||
return "<static file>";
|
||||
}
|
||||
public override string GetHelpText()
|
||||
{
|
||||
return "Deletes the specified file from the static tree.";
|
||||
}
|
||||
}
|
||||
|
||||
class ConfigListCommand : Command
|
||||
{
|
||||
|
||||
Generated
+142
@@ -148,6 +148,16 @@
|
||||
this.RepoProgressBarLabel = new System.Windows.Forms.Label();
|
||||
this.RepoProgressBar = new System.Windows.Forms.ProgressBar();
|
||||
this.Panels = new System.Windows.Forms.TabControl();
|
||||
this.StaticPanel = new System.Windows.Forms.TabPage();
|
||||
this.StaticFileDownloadButton = new System.Windows.Forms.Button();
|
||||
this.StaticFilesRefreshButton = new System.Windows.Forms.Button();
|
||||
this.StaticFileUploadButton = new System.Windows.Forms.Button();
|
||||
this.StaticFileEditTextbox = new System.Windows.Forms.TextBox();
|
||||
this.StaticFileDeleteButton = new System.Windows.Forms.Button();
|
||||
this.StaticFileSaveButton = new System.Windows.Forms.Button();
|
||||
this.StaticFileCreateButton = new System.Windows.Forms.Button();
|
||||
this.label6 = new System.Windows.Forms.Label();
|
||||
this.StaticFileListBox = new System.Windows.Forms.ListBox();
|
||||
this.ChatPanel.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.ChatPortSelector)).BeginInit();
|
||||
this.ChatProviderSelectorPanel.SuspendLayout();
|
||||
@@ -161,6 +171,7 @@
|
||||
this.RepoPanel.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.TestmergeSelector)).BeginInit();
|
||||
this.Panels.SuspendLayout();
|
||||
this.StaticPanel.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// RepoBGW
|
||||
@@ -1598,12 +1609,131 @@
|
||||
this.Panels.Controls.Add(this.BYONDPanel);
|
||||
this.Panels.Controls.Add(this.ServerPanel);
|
||||
this.Panels.Controls.Add(this.ChatPanel);
|
||||
this.Panels.Controls.Add(this.StaticPanel);
|
||||
this.Panels.Cursor = System.Windows.Forms.Cursors.Default;
|
||||
this.Panels.Location = new System.Drawing.Point(12, 12);
|
||||
this.Panels.Name = "Panels";
|
||||
this.Panels.SelectedIndex = 0;
|
||||
this.Panels.Size = new System.Drawing.Size(876, 392);
|
||||
this.Panels.TabIndex = 3;
|
||||
//
|
||||
// StaticPanel
|
||||
//
|
||||
this.StaticPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(39)))), ((int)(((byte)(40)))), ((int)(((byte)(34)))));
|
||||
this.StaticPanel.Controls.Add(this.StaticFileDownloadButton);
|
||||
this.StaticPanel.Controls.Add(this.StaticFilesRefreshButton);
|
||||
this.StaticPanel.Controls.Add(this.StaticFileUploadButton);
|
||||
this.StaticPanel.Controls.Add(this.StaticFileEditTextbox);
|
||||
this.StaticPanel.Controls.Add(this.StaticFileDeleteButton);
|
||||
this.StaticPanel.Controls.Add(this.StaticFileSaveButton);
|
||||
this.StaticPanel.Controls.Add(this.StaticFileCreateButton);
|
||||
this.StaticPanel.Controls.Add(this.label6);
|
||||
this.StaticPanel.Controls.Add(this.StaticFileListBox);
|
||||
this.StaticPanel.Location = new System.Drawing.Point(4, 22);
|
||||
this.StaticPanel.Name = "StaticPanel";
|
||||
this.StaticPanel.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.StaticPanel.Size = new System.Drawing.Size(868, 366);
|
||||
this.StaticPanel.TabIndex = 5;
|
||||
this.StaticPanel.Text = "Static Files";
|
||||
//
|
||||
// StaticFileDownloadButton
|
||||
//
|
||||
this.StaticFileDownloadButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.StaticFileDownloadButton.Location = new System.Drawing.Point(296, 6);
|
||||
this.StaticFileDownloadButton.Name = "StaticFileDownloadButton";
|
||||
this.StaticFileDownloadButton.Size = new System.Drawing.Size(71, 22);
|
||||
this.StaticFileDownloadButton.TabIndex = 32;
|
||||
this.StaticFileDownloadButton.Text = "Download";
|
||||
this.StaticFileDownloadButton.UseVisualStyleBackColor = true;
|
||||
this.StaticFileDownloadButton.Click += new System.EventHandler(this.StaticFileDownloadButton_Click);
|
||||
//
|
||||
// StaticFilesRefreshButton
|
||||
//
|
||||
this.StaticFilesRefreshButton.Location = new System.Drawing.Point(65, 6);
|
||||
this.StaticFilesRefreshButton.Name = "StaticFilesRefreshButton";
|
||||
this.StaticFilesRefreshButton.Size = new System.Drawing.Size(71, 22);
|
||||
this.StaticFilesRefreshButton.TabIndex = 31;
|
||||
this.StaticFilesRefreshButton.Text = "Refresh";
|
||||
this.StaticFilesRefreshButton.UseVisualStyleBackColor = true;
|
||||
this.StaticFilesRefreshButton.Click += new System.EventHandler(this.StaticFilesRefreshButton_Click);
|
||||
//
|
||||
// StaticFileUploadButton
|
||||
//
|
||||
this.StaticFileUploadButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.StaticFileUploadButton.Location = new System.Drawing.Point(219, 6);
|
||||
this.StaticFileUploadButton.Name = "StaticFileUploadButton";
|
||||
this.StaticFileUploadButton.Size = new System.Drawing.Size(71, 22);
|
||||
this.StaticFileUploadButton.TabIndex = 30;
|
||||
this.StaticFileUploadButton.Text = "Upload";
|
||||
this.StaticFileUploadButton.UseVisualStyleBackColor = true;
|
||||
this.StaticFileUploadButton.Click += new System.EventHandler(this.StaticFileUploadButton_Click);
|
||||
//
|
||||
// StaticFileEditTextbox
|
||||
//
|
||||
this.StaticFileEditTextbox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.StaticFileEditTextbox.Location = new System.Drawing.Point(219, 31);
|
||||
this.StaticFileEditTextbox.Multiline = true;
|
||||
this.StaticFileEditTextbox.Name = "StaticFileEditTextbox";
|
||||
this.StaticFileEditTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||
this.StaticFileEditTextbox.Size = new System.Drawing.Size(643, 329);
|
||||
this.StaticFileEditTextbox.TabIndex = 29;
|
||||
//
|
||||
// StaticFileDeleteButton
|
||||
//
|
||||
this.StaticFileDeleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.StaticFileDeleteButton.Location = new System.Drawing.Point(714, 6);
|
||||
this.StaticFileDeleteButton.Name = "StaticFileDeleteButton";
|
||||
this.StaticFileDeleteButton.Size = new System.Drawing.Size(71, 22);
|
||||
this.StaticFileDeleteButton.TabIndex = 28;
|
||||
this.StaticFileDeleteButton.Text = "Delete";
|
||||
this.StaticFileDeleteButton.UseVisualStyleBackColor = true;
|
||||
this.StaticFileDeleteButton.Click += new System.EventHandler(this.StaticFileDeleteButton_Click);
|
||||
//
|
||||
// StaticFileSaveButton
|
||||
//
|
||||
this.StaticFileSaveButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.StaticFileSaveButton.Location = new System.Drawing.Point(791, 6);
|
||||
this.StaticFileSaveButton.Name = "StaticFileSaveButton";
|
||||
this.StaticFileSaveButton.Size = new System.Drawing.Size(71, 22);
|
||||
this.StaticFileSaveButton.TabIndex = 27;
|
||||
this.StaticFileSaveButton.Text = "Save";
|
||||
this.StaticFileSaveButton.UseVisualStyleBackColor = true;
|
||||
this.StaticFileSaveButton.Click += new System.EventHandler(this.StaticFileSaveButton_Click);
|
||||
//
|
||||
// StaticFileCreateButton
|
||||
//
|
||||
this.StaticFileCreateButton.Location = new System.Drawing.Point(142, 6);
|
||||
this.StaticFileCreateButton.Name = "StaticFileCreateButton";
|
||||
this.StaticFileCreateButton.Size = new System.Drawing.Size(71, 22);
|
||||
this.StaticFileCreateButton.TabIndex = 26;
|
||||
this.StaticFileCreateButton.Text = "Add";
|
||||
this.StaticFileCreateButton.UseVisualStyleBackColor = true;
|
||||
this.StaticFileCreateButton.Click += new System.EventHandler(this.StaticFileCreateButton_Click);
|
||||
//
|
||||
// label6
|
||||
//
|
||||
this.label6.AutoSize = true;
|
||||
this.label6.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.label6.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242)))));
|
||||
this.label6.Location = new System.Drawing.Point(6, 10);
|
||||
this.label6.Name = "label6";
|
||||
this.label6.Size = new System.Drawing.Size(53, 18);
|
||||
this.label6.TabIndex = 14;
|
||||
this.label6.Text = "Files:";
|
||||
this.label6.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// StaticFileListBox
|
||||
//
|
||||
this.StaticFileListBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.StaticFileListBox.FormattingEnabled = true;
|
||||
this.StaticFileListBox.HorizontalScrollbar = true;
|
||||
this.StaticFileListBox.Location = new System.Drawing.Point(6, 31);
|
||||
this.StaticFileListBox.Name = "StaticFileListBox";
|
||||
this.StaticFileListBox.Size = new System.Drawing.Size(207, 329);
|
||||
this.StaticFileListBox.TabIndex = 0;
|
||||
this.StaticFileListBox.SelectedIndexChanged += new System.EventHandler(this.StaticFileListBox_SelectedIndexChanged);
|
||||
//
|
||||
// Main
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
@@ -1634,6 +1764,8 @@
|
||||
this.RepoPanel.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.TestmergeSelector)).EndInit();
|
||||
this.Panels.ResumeLayout(false);
|
||||
this.StaticPanel.ResumeLayout(false);
|
||||
this.StaticPanel.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
@@ -1757,5 +1889,15 @@
|
||||
private System.Windows.Forms.Label RepoProgressBarLabel;
|
||||
private System.Windows.Forms.ProgressBar RepoProgressBar;
|
||||
private System.Windows.Forms.TabControl Panels;
|
||||
private System.Windows.Forms.TabPage StaticPanel;
|
||||
private System.Windows.Forms.Button StaticFileCreateButton;
|
||||
private System.Windows.Forms.Label label6;
|
||||
private System.Windows.Forms.ListBox StaticFileListBox;
|
||||
private System.Windows.Forms.Button StaticFileUploadButton;
|
||||
private System.Windows.Forms.TextBox StaticFileEditTextbox;
|
||||
private System.Windows.Forms.Button StaticFileDeleteButton;
|
||||
private System.Windows.Forms.Button StaticFileSaveButton;
|
||||
private System.Windows.Forms.Button StaticFilesRefreshButton;
|
||||
private System.Windows.Forms.Button StaticFileDownloadButton;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace TGControlPanel
|
||||
InitBYONDPage();
|
||||
InitServerPage();
|
||||
LoadChatPage();
|
||||
InitStaticPage();
|
||||
}
|
||||
|
||||
private void Main_Resize(object sender, EventArgs e)
|
||||
@@ -28,5 +29,6 @@ namespace TGControlPanel
|
||||
{
|
||||
Properties.Settings.Default.LastPageIndex = Panels.SelectedIndex;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +130,7 @@ namespace TGControlPanel
|
||||
ResetTestmerge.Visible = RepoExists;
|
||||
WorldAnnounceField.Visible = RepoExists;
|
||||
WorldAnnounceButton.Visible = RepoExists;
|
||||
WorldAnnounceLabel.Visible = RepoExists;
|
||||
|
||||
var DM = Server.GetComponent<ITGCompiler>();
|
||||
var DD = Server.GetComponent<ITGDreamDaemon>();
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using TGServiceInterface;
|
||||
|
||||
namespace TGControlPanel
|
||||
{
|
||||
partial class Main
|
||||
{
|
||||
IDictionary<int, string> IndexesToPaths = new Dictionary<int, string>();
|
||||
void InitStaticPage()
|
||||
{
|
||||
BuildFileList();
|
||||
}
|
||||
|
||||
void BuildFileList()
|
||||
{
|
||||
IndexesToPaths.Clear();
|
||||
StaticFileListBox.Items.Clear();
|
||||
IndexesToPaths.Add(StaticFileListBox.Items.Add("/"), "/");
|
||||
if (!EnumeratePath("", Server.GetComponent<ITGConfig>(), 1))
|
||||
{
|
||||
StaticFileListBox.Items[0] += " (UNAUTHORIZED)";
|
||||
IndexesToPaths[0] = null;
|
||||
}
|
||||
StaticFileListBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
bool EnumeratePath(string path, ITGConfig config, int level)
|
||||
{
|
||||
var Enum = config.ListStaticDirectory(path, out string error, out bool unauthorized);
|
||||
if(Enum == null)
|
||||
{
|
||||
if (unauthorized)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
MessageBox.Show(String.Format("Could not enumerate static path \"{0}\" error: {1}", path, error));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
foreach(var I in Enum)
|
||||
{
|
||||
if(I[0] == '/')
|
||||
{
|
||||
var dir = I.Remove(0, 1);
|
||||
var index = StaticFileListBox.Items.Add(DSNTimes(level) + dir + '/');
|
||||
var fullpath = path + '/' + dir;
|
||||
IndexesToPaths.Add(index, fullpath);
|
||||
if (!EnumeratePath(fullpath, config, level + 1))
|
||||
{
|
||||
StaticFileListBox.Items[index] += " (UNAUTHORIZED)";
|
||||
IndexesToPaths[index] = null;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
IndexesToPaths.Add(StaticFileListBox.Items.Add(DSNTimes(level) + I), Path.Combine(path, I));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string DSNTimes(int n)
|
||||
{
|
||||
var res = "";
|
||||
for (var I = 0; I < n; ++I)
|
||||
res += " ";
|
||||
return res;
|
||||
}
|
||||
private void StaticFilesRefreshButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
BuildFileList();
|
||||
}
|
||||
|
||||
private void StaticFileUploadButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (StaticFileEditTextbox.Text != "Directory")
|
||||
{
|
||||
MessageBox.Show("Please select a directory to upload the file to.");
|
||||
return;
|
||||
}
|
||||
var ofd = new OpenFileDialog()
|
||||
{
|
||||
CheckFileExists = true,
|
||||
CheckPathExists = true,
|
||||
DefaultExt = ".txt",
|
||||
Multiselect = false,
|
||||
Title = "Static File Upload",
|
||||
ValidateNames = true,
|
||||
Filter = "All files (*.*)|*.*",
|
||||
AddExtension = false,
|
||||
SupportMultiDottedExtensions = true,
|
||||
};
|
||||
if (ofd.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var fileToUpload = ofd.FileName;
|
||||
|
||||
var FileName = Path.Combine(IndexesToPaths[StaticFileListBox.SelectedIndex], Path.GetFileName(fileToUpload));
|
||||
|
||||
string fileContents = null;
|
||||
string error = null;
|
||||
try
|
||||
{
|
||||
fileContents = File.ReadAllText(fileToUpload);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
}
|
||||
if (error == null)
|
||||
try
|
||||
{
|
||||
error = Server.GetComponent<ITGConfig>().WriteText(FileName, fileContents, out bool unauthorized);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = "Failed to read file, most likely due to it being too large. The transfer limit is much higher on non-remote connections. " + ex.ToString();
|
||||
}
|
||||
if (error != null)
|
||||
MessageBox.Show("An error occurred: " + error);
|
||||
BuildFileList();
|
||||
}
|
||||
|
||||
private void StaticFileDownloadButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (StaticFileEditTextbox.ReadOnly)
|
||||
{
|
||||
MessageBox.Show("Cannot download this file!");
|
||||
return;
|
||||
}
|
||||
var remotePath = IndexesToPaths[StaticFileListBox.SelectedIndex];
|
||||
if (remotePath == null)
|
||||
return;
|
||||
string text, error;
|
||||
try
|
||||
{
|
||||
text = Server.GetComponent<ITGConfig>().ReadText(remotePath, false, out error, out bool unauthorized);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
text = null;
|
||||
error = "Failed to read file, most likely due to it being too large. The transfer limit is much higher on non-remote connections. " + ex.ToString();
|
||||
}
|
||||
if (text != null)
|
||||
{
|
||||
var ofd = new SaveFileDialog()
|
||||
{
|
||||
CheckFileExists = false,
|
||||
CheckPathExists = true,
|
||||
DefaultExt = ".txt",
|
||||
Title = "Static File Download",
|
||||
ValidateNames = true,
|
||||
Filter = "All files (*.*)|*.*",
|
||||
AddExtension = false,
|
||||
CreatePrompt = false,
|
||||
OverwritePrompt = true,
|
||||
SupportMultiDottedExtensions = true,
|
||||
};
|
||||
if (ofd.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(ofd.FileName, text);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
}
|
||||
}
|
||||
MessageBox.Show("An error occurred: " + error);
|
||||
}
|
||||
|
||||
private void StaticFileDeleteButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (MessageBox.Show("Are you sure you want to delete " + ((string)StaticFileListBox.SelectedItem).Trim() + "?", "Confirm", MessageBoxButtons.YesNo) != DialogResult.Yes)
|
||||
return;
|
||||
var res = Server.GetComponent<ITGConfig>().DeleteFile(IndexesToPaths[StaticFileListBox.SelectedIndex], out bool unauthorized);
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
BuildFileList();
|
||||
}
|
||||
|
||||
private void StaticFileCreateButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if(StaticFileEditTextbox.Text != "Directory")
|
||||
{
|
||||
MessageBox.Show("Please select a directory to create the file in.");
|
||||
return;
|
||||
}
|
||||
var FileName = Program.TextPrompt("Static File/Directory Creation", "Enter the name of the file/directory:");
|
||||
if (FileName == null)
|
||||
return;
|
||||
|
||||
var resu = MessageBox.Show("Is this the name of a directory?", "Directory", MessageBoxButtons.YesNoCancel);
|
||||
if (resu == DialogResult.Cancel)
|
||||
return;
|
||||
var FullFileName = Path.Combine(IndexesToPaths[StaticFileListBox.SelectedIndex], FileName);
|
||||
if (resu == DialogResult.Yes)
|
||||
FullFileName = Path.Combine(FullFileName, "__TGS3_CP_DIRECTORY_CREATOR__");
|
||||
var config = Server.GetComponent<ITGConfig>();
|
||||
var res = config.WriteText(FullFileName, "", out bool unauthorized);
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
if (resu == DialogResult.Yes)
|
||||
{
|
||||
FullFileName = Path.Combine(FullFileName, "__TGS3_CP_DIRECTORY_CREATOR__");
|
||||
config.DeleteFile(FullFileName, out unauthorized); //don't care about this
|
||||
}
|
||||
BuildFileList();
|
||||
}
|
||||
|
||||
private void StaticFileSaveButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var index = StaticFileListBox.SelectedIndex;
|
||||
string res;
|
||||
bool unauthorized;
|
||||
try
|
||||
{
|
||||
res = Server.GetComponent<ITGConfig>().WriteText(IndexesToPaths[index], StaticFileEditTextbox.Text, out unauthorized);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
unauthorized = false;
|
||||
res = "Failed to write file, most likely due to it being too large. The transfer limit is much higher on non-remote connections. " + ex.ToString();
|
||||
}
|
||||
if (res != null)
|
||||
{
|
||||
MessageBox.Show("Error: " + res);
|
||||
var title = (string)StaticFileListBox.Items[index];
|
||||
if (unauthorized && !title.Contains(" (UNAUTHORIZED)"))
|
||||
StaticFileListBox.Items[index] = title + " (UNAUTHORIZED)";
|
||||
}
|
||||
}
|
||||
|
||||
private void StaticFileListBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdateEditText();
|
||||
}
|
||||
|
||||
void UpdateEditText()
|
||||
{
|
||||
var newIndex = StaticFileListBox.SelectedIndex;
|
||||
var path = IndexesToPaths[newIndex];
|
||||
var title = (string)StaticFileListBox.Items[newIndex];
|
||||
var authed_title = title.Replace(" (UNAUTHORIZED)", "");
|
||||
if (authed_title[authed_title.Length - 1] == '/')
|
||||
{
|
||||
StaticFileEditTextbox.ReadOnly = true;
|
||||
StaticFileEditTextbox.Text = "Directory";
|
||||
}
|
||||
else
|
||||
{
|
||||
string entry, error;
|
||||
bool unauthorized;
|
||||
try
|
||||
{
|
||||
entry = Server.GetComponent<ITGConfig>().ReadText(path, false, out error, out unauthorized);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
entry = null;
|
||||
unauthorized = false;
|
||||
error = "Failed to read file, most likely due to it being too large. The transfer limit is much higher on non-remote connections. " + e.ToString();
|
||||
}
|
||||
if (entry == null)
|
||||
{
|
||||
StaticFileEditTextbox.ReadOnly = true;
|
||||
StaticFileEditTextbox.Text = "ERROR: " + error;
|
||||
if (unauthorized && !title.Contains(" (UNAUTHORIZED)"))
|
||||
StaticFileListBox.Items[newIndex] = title + " (UNAUTHORIZED)";
|
||||
}
|
||||
else
|
||||
{
|
||||
StaticFileEditTextbox.ReadOnly = false;
|
||||
StaticFileEditTextbox.Text = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,9 @@
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="..\Version.cs" />
|
||||
<Compile Include="StaticPage.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="Login.resx">
|
||||
<DependentUpon>Login.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
||||
@@ -203,8 +203,8 @@ namespace TGServerService
|
||||
CreateSymlink(Path.Combine(GameDirA, I), Path.Combine(StaticDirs, I));
|
||||
}
|
||||
|
||||
CreateSymlink(Path.Combine(GameDirA, InterfaceDLLName), Path.Combine(StaticDirs, InterfaceDLLName));
|
||||
CreateSymlink(Path.Combine(GameDirB, InterfaceDLLName), Path.Combine(StaticDirs, InterfaceDLLName));
|
||||
CreateSymlink(Path.Combine(GameDirA, InterfaceDLLName), InterfaceDLLName);
|
||||
CreateSymlink(Path.Combine(GameDirB, InterfaceDLLName), InterfaceDLLName);
|
||||
|
||||
CreateSymlink(GameDirLive, GameDirA);
|
||||
|
||||
@@ -344,7 +344,7 @@ namespace TGServerService
|
||||
}
|
||||
|
||||
if (!File.Exists(Path.Combine(resurrectee, InterfaceDLLName)))
|
||||
CreateSymlink(Path.Combine(resurrectee, InterfaceDLLName), Path.Combine(StaticDirs, InterfaceDLLName));
|
||||
CreateSymlink(Path.Combine(resurrectee, InterfaceDLLName), InterfaceDLLName);
|
||||
|
||||
bool repobusy_check = false;
|
||||
if (!Monitor.TryEnter(RepoLock))
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace TGServerService
|
||||
{
|
||||
var configDir = repo ? RepoPath : StaticDirs;
|
||||
|
||||
var path = Path.Combine(configDir, staticRelativePath);
|
||||
var path = configDir + '/' + staticRelativePath; //do not use path.combine or it will try and take the root
|
||||
lock (configLock)
|
||||
{
|
||||
var di1 = new DirectoryInfo(configDir);
|
||||
@@ -77,9 +77,12 @@ namespace TGServerService
|
||||
return null;
|
||||
}
|
||||
|
||||
var output = File.ReadAllText(path);
|
||||
TGServerService.CancelImpersonation();
|
||||
TGServerService.WriteInfo("Read of " + path, TGServerService.EventID.StaticRead);
|
||||
error = null;
|
||||
unauthorized = false;
|
||||
return File.ReadAllText(path);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException e)
|
||||
@@ -101,7 +104,7 @@ namespace TGServerService
|
||||
{
|
||||
try
|
||||
{
|
||||
var path = Path.Combine(StaticDirs, staticRelativePath);
|
||||
var path = StaticDirs + '/' + staticRelativePath; //do not use path.combine or it will try and take the root
|
||||
lock (configLock)
|
||||
{
|
||||
var di1 = new DirectoryInfo(StaticDirs);
|
||||
@@ -127,6 +130,59 @@ namespace TGServerService
|
||||
|
||||
Directory.CreateDirectory(destdir);
|
||||
File.WriteAllText(path, data);
|
||||
TGServerService.CancelImpersonation();
|
||||
TGServerService.WriteInfo("Write to " + path, TGServerService.EventID.StaticWrite);
|
||||
unauthorized = false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException e)
|
||||
{
|
||||
//no need for the full stacktrace
|
||||
unauthorized = true;
|
||||
return e.Message;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
unauthorized = false;
|
||||
return e.ToString();
|
||||
}
|
||||
}
|
||||
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
|
||||
public string DeleteFile(string staticRelativePath, out bool unauthorized)
|
||||
{
|
||||
try
|
||||
{
|
||||
var path = StaticDirs + '/' + staticRelativePath; //do not use path.combine or it will try and take the root
|
||||
lock (configLock)
|
||||
{
|
||||
var di1 = new DirectoryInfo(StaticDirs);
|
||||
var fi = new FileInfo(path);
|
||||
var di2 = new DirectoryInfo(fi.Directory.FullName);
|
||||
|
||||
var good = false;
|
||||
while (di2 != null)
|
||||
{
|
||||
if (di2.FullName == di1.FullName)
|
||||
{
|
||||
good = true;
|
||||
break;
|
||||
}
|
||||
else di2 = di2.Parent;
|
||||
}
|
||||
|
||||
if (!good)
|
||||
{
|
||||
unauthorized = false;
|
||||
return "Cannot delete above static directories!";
|
||||
}
|
||||
|
||||
if (fi.Exists)
|
||||
File.Delete(path);
|
||||
else if (Directory.Exists(path))
|
||||
Program.DeleteDirectory(path);
|
||||
TGServerService.CancelImpersonation();
|
||||
TGServerService.WriteInfo("Delete of " + path, TGServerService.EventID.StaticDelete);
|
||||
unauthorized = false;
|
||||
return null;
|
||||
}
|
||||
@@ -149,7 +205,13 @@ namespace TGServerService
|
||||
{
|
||||
try
|
||||
{
|
||||
DirectoryInfo dirToEnum = new DirectoryInfo(Path.Combine(StaticDirs, subDir ?? ""));
|
||||
if (!Directory.Exists(StaticDirs))
|
||||
{
|
||||
error = null;
|
||||
unauthorized = false;
|
||||
return new List<string>();
|
||||
}
|
||||
DirectoryInfo dirToEnum = new DirectoryInfo(StaticDirs + '/' + subDir ?? ""); //do not use path.combine or it will try and take the root
|
||||
var result = new List<string>();
|
||||
foreach (var I in dirToEnum.GetFiles())
|
||||
result.Add(I.Name);
|
||||
|
||||
@@ -368,12 +368,11 @@ namespace TGServerService
|
||||
|
||||
void UpdateInterfaceDll(bool overwrite)
|
||||
{
|
||||
var targetPath = Path.Combine(StaticDirs, InterfaceDLLName);
|
||||
if (File.Exists(targetPath) && !overwrite)
|
||||
if (File.Exists(InterfaceDLLName) && !overwrite)
|
||||
return;
|
||||
//Copy the interface dll to the static dir
|
||||
var InterfacePath = Assembly.GetAssembly(typeof(DDInteropCallHolder)).Location;
|
||||
Program.CopyFileForceDirectories(InterfacePath, targetPath, true);
|
||||
File.Copy(InterfacePath, InterfaceDLLName, overwrite);
|
||||
}
|
||||
|
||||
//used by Start and Watchdog to start a DD instance
|
||||
|
||||
@@ -35,6 +35,13 @@ namespace TGServerService
|
||||
/// </summary>
|
||||
class RepoConfig
|
||||
{
|
||||
IList<string> LoadArray(object o) {
|
||||
var array = (object[])o;
|
||||
var res = new List<string>();
|
||||
foreach (var I in array)
|
||||
res.Add((string)I);
|
||||
return res;
|
||||
}
|
||||
public RepoConfig()
|
||||
{
|
||||
if (!File.Exists(RepoTGS3SettingsPath))
|
||||
@@ -50,12 +57,12 @@ namespace TGServerService
|
||||
ChangelogSupport = true;
|
||||
try
|
||||
{
|
||||
PipDependancies = (IList<string>)details["pip_dependancies"];
|
||||
PipDependancies = LoadArray(details["pip_dependancies"]);
|
||||
}
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
ChangelogPathsToStage = (IList<string>)details["synchronize_paths"];
|
||||
ChangelogPathsToStage = LoadArray(details["synchronize_paths"]);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
@@ -64,12 +71,12 @@ namespace TGServerService
|
||||
}
|
||||
try
|
||||
{
|
||||
StaticDirectoryPaths = (IList<string>)json["static_directories"];
|
||||
StaticDirectoryPaths = LoadArray(json["static_directories"]);
|
||||
}
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
DLLPaths = (IList<string>)json["dlls"];
|
||||
DLLPaths = LoadArray(json["dlls"]);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Security.Principal;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceProcess;
|
||||
using TGServiceInterface;
|
||||
@@ -81,12 +82,23 @@ namespace TGServerService
|
||||
InteropCallException = 7000,
|
||||
APIVersionMismatch = 7100,
|
||||
RepoConfigurationFail = 7200,
|
||||
StaticRead = 7300,
|
||||
StaticWrite = 7400,
|
||||
StaticDelete = 7500,
|
||||
}
|
||||
|
||||
static TGServerService ActiveService; //So everyone else can write to our eventlog
|
||||
|
||||
public static readonly string Version = "/tg/station 13 Server Service v" + FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).FileVersion;
|
||||
|
||||
/// <summary>
|
||||
/// You can't write to logs while impersonating, call this to cancel WCF's impersonation first
|
||||
/// </summary>
|
||||
public static void CancelImpersonation()
|
||||
{
|
||||
WindowsIdentity.Impersonate(IntPtr.Zero);
|
||||
}
|
||||
|
||||
public static void WriteInfo(string message, EventID id)
|
||||
{
|
||||
ActiveService.EventLog.WriteEntry(message, EventLogEntryType.Information, (int)id);
|
||||
@@ -196,8 +208,12 @@ namespace TGServerService
|
||||
void AddEndpoint(Type typetype)
|
||||
{
|
||||
var bindingName = Server.MasterInterfaceName + "/" + typetype.Name;
|
||||
host.AddServiceEndpoint(typetype, new NetNamedPipeBinding(), bindingName);
|
||||
var httpsBinding = new WSHttpBinding();
|
||||
host.AddServiceEndpoint(typetype, new NetNamedPipeBinding() { SendTimeout = new TimeSpan(0, 0, 30), MaxReceivedMessageSize = Server.TransferLimitLocal }, bindingName);
|
||||
var httpsBinding = new WSHttpBinding()
|
||||
{
|
||||
SendTimeout = new TimeSpan(0, 0, 40),
|
||||
MaxReceivedMessageSize = Server.TransferLimitRemote
|
||||
};
|
||||
var requireAuth = typetype.Name != typeof(ITGConnectivity).Name;
|
||||
httpsBinding.Security.Mode = requireAuth ? SecurityMode.TransportWithMessageCredential : SecurityMode.Transport; //do not require auth for a connectivity check
|
||||
httpsBinding.Security.Message.ClientCredentialType = requireAuth ? MessageCredentialType.UserName : MessageCredentialType.None;
|
||||
|
||||
@@ -30,24 +30,35 @@ namespace TGServiceInterface
|
||||
IList<string> ListStaticDirectory(string subpath, out string error, out bool unauthorized);
|
||||
|
||||
/// <summary>
|
||||
/// For when you really just need to see the raw data of the config
|
||||
/// Read from a static file
|
||||
/// </summary>
|
||||
/// <param name="staticRelativePath">The path from the Static dir. E.g. config/config.txt</param>
|
||||
/// <param name="repo">if true, the file will be read from the repository instead of the static dir</param>
|
||||
/// <param name="error">null on success, error message on failure</param>
|
||||
/// <param name="unauthorized">This will be true if error is set to a message that indicates the current user does not have access to the specified file</param>
|
||||
/// <returns>The full text of the file on success, null on failure</returns>
|
||||
/// <exception cref="CommunicationException">Along with implied disconnect exceptions, if the file exceeds transfer limits</exception>
|
||||
[OperationContract]
|
||||
string ReadText(string staticRelativePath, bool repo, out string error, out bool unauthorized);
|
||||
|
||||
/// <summary>
|
||||
/// For when you really just need to set the raw data of the config
|
||||
/// Write to a static file
|
||||
/// </summary>
|
||||
/// <param name="configRelativePath">The path from the configDir. E.g. config.txt</param>
|
||||
/// <param name="staticRelativePath">The path from the Static dir. E.g. config/config.txt</param>
|
||||
/// <param name="data">The full text of the config file</param>
|
||||
/// <param name="unauthorized">This will be true if error is set to a message that indicates the current user does not have access to the specified file</param>
|
||||
/// <returns>null on success, error message on failure</returns>
|
||||
/// <exception cref="CommunicationException">Along with implied disconnect exceptions, if the file exceeds transfer limits</exception>
|
||||
[OperationContract]
|
||||
string WriteText(string staticRelativePath, string data, out bool unauthorized);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the target static file
|
||||
/// </summary>
|
||||
/// <param name="staticRelativePath">The path from the Static dir. E.g. config/config.txt</param>
|
||||
/// <param name="unauthorized">This will be true if error is set to a message that indicates the current user does not have access to the specified file</param>
|
||||
/// <returns>null on success, error message on failure</returns>
|
||||
[OperationContract]
|
||||
string DeleteFile(string staticRelativePath, out bool unauthorized);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,16 @@ namespace TGServiceInterface
|
||||
/// </summary>
|
||||
public static readonly IList<Type> ValidInterfaces = new List<Type> { typeof(ITGByond), typeof(ITGChat), typeof(ITGCompiler), typeof(ITGConfig), typeof(ITGDreamDaemon), typeof(ITGRepository), typeof(ITGSService), typeof(ITGConnectivity), typeof(ITGAdministration), typeof(ITGInterop) };
|
||||
|
||||
/// <summary>
|
||||
/// The maximum message size to and from a local server
|
||||
/// </summary>
|
||||
public static readonly long TransferLimitLocal = Int32.MaxValue; //2GB can't go higher
|
||||
|
||||
/// <summary>
|
||||
/// The maximum message size to and from a remote server
|
||||
/// </summary>
|
||||
public static readonly long TransferLimitRemote = 10485760; //10 MB
|
||||
|
||||
/// <summary>
|
||||
/// Base name of the communication pipe
|
||||
/// they are formatted as MasterPipeName/ComponentName
|
||||
@@ -107,7 +117,8 @@ namespace TGServiceInterface
|
||||
var InterfaceName = typeof(T).Name;
|
||||
if (HTTPSURL == null)
|
||||
{
|
||||
outChannel = new ChannelFactory<T>(new NetNamedPipeBinding { SendTimeout = new TimeSpan(0, 10, 0) }, new EndpointAddress(String.Format("net.pipe://localhost/{0}/{1}", MasterInterfaceName, InterfaceName)));
|
||||
outChannel = new ChannelFactory<T>(
|
||||
new NetNamedPipeBinding { SendTimeout = new TimeSpan(0, 0, 30), MaxReceivedMessageSize = TransferLimitLocal }, new EndpointAddress(String.Format("net.pipe://localhost/{0}/{1}", MasterInterfaceName, InterfaceName))); //10 megs
|
||||
outChannel.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
|
||||
return outChannel.CreateChannel();
|
||||
}
|
||||
@@ -115,7 +126,8 @@ namespace TGServiceInterface
|
||||
//okay we're going over
|
||||
var binding = new WSHttpBinding()
|
||||
{
|
||||
SendTimeout = new TimeSpan(0, 10, 0)
|
||||
SendTimeout = new TimeSpan(0, 0, 40),
|
||||
MaxReceivedMessageSize = TransferLimitRemote
|
||||
};
|
||||
var requireAuth = InterfaceName != typeof(ITGConnectivity).Name;
|
||||
binding.Security.Mode = requireAuth ? SecurityMode.TransportWithMessageCredential : SecurityMode.Transport; //do not require auth for a connectivity check
|
||||
|
||||
Reference in New Issue
Block a user