mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Add support request desktop shortcut.
This commit is contained in:
parent
50d407b8d8
commit
f07abd16f5
@ -175,6 +175,17 @@
|
||||
<ItemGroup>
|
||||
<Resource Include="Assets\Remotely_Icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<COMReference Include="IWshRuntimeLibrary">
|
||||
<Guid>{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>if $(ConfigurationName) == Debug (
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using Microsoft.VisualBasic.FileIO;
|
||||
using IWshRuntimeLibrary;
|
||||
using Microsoft.VisualBasic.FileIO;
|
||||
using Microsoft.Win32;
|
||||
using Remotely.Shared.Models;
|
||||
using System;
|
||||
@ -15,6 +16,7 @@ using System.ServiceProcess;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Script.Serialization;
|
||||
using System.Windows;
|
||||
using FileIO = System.IO.File;
|
||||
|
||||
namespace Remotely.Agent.Installer.Win.Services
|
||||
{
|
||||
@ -55,9 +57,9 @@ namespace Remotely.Agent.Installer.Win.Services
|
||||
|
||||
await DownloadRemotelyAgent(serverUrl);
|
||||
|
||||
File.WriteAllText(Path.Combine(InstallPath, "ConnectionInfo.json"), Serializer.Serialize(connectionInfo));
|
||||
FileIO.WriteAllText(Path.Combine(InstallPath, "ConnectionInfo.json"), Serializer.Serialize(connectionInfo));
|
||||
|
||||
File.Copy(Assembly.GetExecutingAssembly().Location, Path.Combine(InstallPath, "Remotely_Installer.exe"));
|
||||
FileIO.Copy(Assembly.GetExecutingAssembly().Location, Path.Combine(InstallPath, "Remotely_Installer.exe"));
|
||||
|
||||
CreateDeviceSetupOptions(deviceGroup, deviceAlias);
|
||||
|
||||
@ -66,6 +68,8 @@ namespace Remotely.Agent.Installer.Win.Services
|
||||
InstallService();
|
||||
|
||||
CreateUninstallKey();
|
||||
|
||||
CreateSupportShortcut(serverUrl, deviceUuid);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -78,6 +82,26 @@ namespace Remotely.Agent.Installer.Win.Services
|
||||
|
||||
}
|
||||
|
||||
private void CreateSupportShortcut(string serverUrl, string deviceUuid)
|
||||
{
|
||||
var systemRoot = Path.GetPathRoot(Environment.SystemDirectory);
|
||||
var shortcutLocation = Path.Combine(systemRoot, "Users", "Public", "Desktop", "Get Support.lnk");
|
||||
var shell = new WshShell();
|
||||
var shortcut = (IWshShortcut)shell.CreateShortcut(shortcutLocation);
|
||||
shortcut.Description = "Get IT support";
|
||||
shortcut.IconLocation = Path.Combine(InstallPath, "Remotely_Agent.exe");
|
||||
shortcut.TargetPath = serverUrl.TrimEnd('/') + $"/GetSupport?deviceID={deviceUuid}";
|
||||
shortcut.Save();
|
||||
|
||||
|
||||
shortcutLocation = Path.Combine(InstallPath, "Get Support.lnk");
|
||||
shortcut = (IWshShortcut)shell.CreateShortcut(shortcutLocation);
|
||||
shortcut.Description = "Get IT support";
|
||||
shortcut.IconLocation = Path.Combine(InstallPath, "Remotely_Agent.exe");
|
||||
shortcut.TargetPath = serverUrl.TrimEnd('/') + $"/GetSupport?deviceID={deviceUuid}";
|
||||
shortcut.Save();
|
||||
}
|
||||
|
||||
public async Task<bool> Uninstall()
|
||||
{
|
||||
try
|
||||
@ -124,9 +148,9 @@ namespace Remotely.Agent.Installer.Win.Services
|
||||
Logger.Write("Backing up current installation.");
|
||||
ProgressMessageChanged?.Invoke(this, "Backing up current installation.");
|
||||
var backupPath = Path.Combine(Path.GetTempPath(), "Remotely_Backup.zip");
|
||||
if (File.Exists(backupPath))
|
||||
if (FileIO.Exists(backupPath))
|
||||
{
|
||||
File.Delete(backupPath);
|
||||
FileIO.Delete(backupPath);
|
||||
}
|
||||
ZipFile.CreateFromDirectory(InstallPath, backupPath, CompressionLevel.Fastest, false);
|
||||
}
|
||||
@ -152,9 +176,9 @@ namespace Remotely.Agent.Installer.Win.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(entry))
|
||||
if (FileIO.Exists(entry))
|
||||
{
|
||||
File.Delete(entry);
|
||||
FileIO.Delete(entry);
|
||||
}
|
||||
else if (Directory.Exists(entry))
|
||||
{
|
||||
@ -180,7 +204,7 @@ namespace Remotely.Agent.Installer.Win.Services
|
||||
DeviceAlias = deviceAlias
|
||||
};
|
||||
|
||||
File.WriteAllText(Path.Combine(InstallPath, "DeviceSetupOptions.json"), Serializer.Serialize(setupOptions));
|
||||
FileIO.WriteAllText(Path.Combine(InstallPath, "DeviceSetupOptions.json"), Serializer.Serialize(setupOptions));
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,7 +231,7 @@ namespace Remotely.Agent.Installer.Win.Services
|
||||
|
||||
if (CommandLineParser.CommandLineArgs.TryGetValue("path", out var result))
|
||||
{
|
||||
File.Copy(result, targetFile, true);
|
||||
FileIO.Copy(result, targetFile, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -239,7 +263,7 @@ namespace Remotely.Agent.Installer.Win.Services
|
||||
var wr = WebRequest.CreateHttp($"{serverUrl}/Downloads/Remotely-Win10-{Platform}.zip");
|
||||
wr.Method = "Head";
|
||||
var response = (HttpWebResponse)await wr.GetResponseAsync();
|
||||
File.WriteAllText(Path.Combine(InstallPath, "etag.txt"), response.Headers["ETag"]);
|
||||
FileIO.WriteAllText(Path.Combine(InstallPath, "etag.txt"), response.Headers["ETag"]);
|
||||
|
||||
ZipFile.ExtractToDirectory(targetFile, tempDir);
|
||||
var fileSystemEntries = Directory.GetFileSystemEntries(tempDir);
|
||||
@ -249,9 +273,9 @@ namespace Remotely.Agent.Installer.Win.Services
|
||||
{
|
||||
ProgressValueChanged?.Invoke(this, (int)((double)i / (double)fileSystemEntries.Length * 100d));
|
||||
var entry = fileSystemEntries[i];
|
||||
if (File.Exists(entry))
|
||||
if (FileIO.Exists(entry))
|
||||
{
|
||||
File.Copy(entry, Path.Combine(InstallPath, Path.GetFileName(entry)), true);
|
||||
FileIO.Copy(entry, Path.Combine(InstallPath, Path.GetFileName(entry)), true);
|
||||
}
|
||||
else if (Directory.Exists(entry))
|
||||
{
|
||||
@ -271,9 +295,9 @@ namespace Remotely.Agent.Installer.Win.Services
|
||||
{
|
||||
ConnectionInfo connectionInfo;
|
||||
var connectionInfoPath = Path.Combine(InstallPath, "ConnectionInfo.json");
|
||||
if (File.Exists(connectionInfoPath))
|
||||
if (FileIO.Exists(connectionInfoPath))
|
||||
{
|
||||
connectionInfo = Serializer.Deserialize<ConnectionInfo>(File.ReadAllText(connectionInfoPath));
|
||||
connectionInfo = Serializer.Deserialize<ConnectionInfo>(FileIO.ReadAllText(connectionInfoPath));
|
||||
connectionInfo.ServerVerificationToken = null;
|
||||
}
|
||||
else
|
||||
@ -393,7 +417,7 @@ namespace Remotely.Agent.Installer.Win.Services
|
||||
try
|
||||
{
|
||||
var backupPath = Path.Combine(Path.GetTempPath(), "Remotely_Backup.zip");
|
||||
if (File.Exists(backupPath))
|
||||
if (FileIO.Exists(backupPath))
|
||||
{
|
||||
Logger.Write("Restoring backup.");
|
||||
ClearInstallDirectory();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Remotely.Server.Auth;
|
||||
using Remotely.Server.Attributes;
|
||||
using Remotely.Server.Services;
|
||||
using Remotely.Shared.Models;
|
||||
using System;
|
||||
|
||||
@ -6,10 +6,10 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Remotely.Server.Services;
|
||||
using Remotely.Server.Auth;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Threading;
|
||||
using Remotely.Server.Attributes;
|
||||
|
||||
namespace Remotely.Server.API
|
||||
{
|
||||
|
||||
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
using Remotely.Shared.Models;
|
||||
using Remotely.Server.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Remotely.Server.Auth;
|
||||
using Remotely.Server.Attributes;
|
||||
|
||||
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ using Remotely.Shared.Models;
|
||||
using Remotely.Server.Services;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Remotely.Server.Auth;
|
||||
using Remotely.Server.Attributes;
|
||||
|
||||
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Remotely.Shared.ViewModels.Organization;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Remotely.Server.Auth;
|
||||
using Remotely.Server.Attributes;
|
||||
|
||||
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ using Microsoft.AspNetCore.SignalR;
|
||||
using Remotely.Shared.Models;
|
||||
using Remotely.Server.Models;
|
||||
using Remotely.Server.Services;
|
||||
using Remotely.Server.Auth;
|
||||
using Remotely.Server.Attributes;
|
||||
using Remotely.Shared.Helpers;
|
||||
|
||||
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
|
||||
|
||||
@ -9,7 +9,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Remotely.Shared.Helpers;
|
||||
using System.IO;
|
||||
using Remotely.Server.Auth;
|
||||
using Remotely.Server.Attributes;
|
||||
|
||||
namespace Remotely.Server.API
|
||||
{
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Remotely.Server.Auth;
|
||||
using Remotely.Server.Attributes;
|
||||
using Remotely.Server.Services;
|
||||
|
||||
namespace Remotely.Server.API
|
||||
|
||||
@ -6,9 +6,9 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Remotely.Server.Auth;
|
||||
using Remotely.Server.Services;
|
||||
using Remotely.Shared.Models;
|
||||
using Remotely.Shared.Utilities;
|
||||
|
||||
namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
|
||||
{
|
||||
|
||||
35
Server/Attributes/ActionRateLimiterAttribute.cs
Normal file
35
Server/Attributes/ActionRateLimiterAttribute.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Remotely.Server.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class ActionRateLimiterAttribute : ActionFilterAttribute
|
||||
{
|
||||
public string Action { get; set; }
|
||||
public int TimeoutInSeconds { get; set; } = 5;
|
||||
private static MemoryCache RequestCache { get; } = new MemoryCache(new MemoryCacheOptions());
|
||||
|
||||
|
||||
public override void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
var ip = context.HttpContext.Request.HttpContext.Connection.RemoteIpAddress;
|
||||
var key = $"Action-{ip}";
|
||||
|
||||
if (!RequestCache.TryGetValue(key, out _))
|
||||
{
|
||||
RequestCache.Set(key, true, TimeSpan.FromSeconds(TimeoutInSeconds));
|
||||
}
|
||||
else
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.TooManyRequests;
|
||||
}
|
||||
base.OnActionExecuting(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Remotely.Server.Services;
|
||||
|
||||
namespace Remotely.Server.Auth
|
||||
namespace Remotely.Server.Attributes
|
||||
{
|
||||
public class ApiAuthorizationFilter : ActionFilterAttribute, IAuthorizationFilter
|
||||
{
|
||||
68
Server/Pages/GetSupport.cshtml
Normal file
68
Server/Pages/GetSupport.cshtml
Normal file
@ -0,0 +1,68 @@
|
||||
@page
|
||||
@model Remotely.Server.Pages.GetSupportModel
|
||||
@{
|
||||
ViewData["Title"] = "Get Support";
|
||||
}
|
||||
|
||||
@if (!Request.Query.ContainsKey("deviceUuid"))
|
||||
{
|
||||
<h3 class="mb-3">Get Support</h3>
|
||||
<p>
|
||||
Device ID is missing. Please use a valid shortcut to the support page, which will include the device ID.
|
||||
</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="col-sm-6 offset-sm-3">
|
||||
@if (!string.IsNullOrWhiteSpace(Model.StatusMessage))
|
||||
{
|
||||
<div class="alert alert-success alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
@Model.StatusMessage
|
||||
</div>
|
||||
}
|
||||
<h3 class="mb-3">Get Support</h3>
|
||||
<form method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label class="col-form-label">Your Name:</label>
|
||||
<br />
|
||||
<input type="text" class="form-control" asp-for="Input.Name" />
|
||||
<span asp-validation-for="Input.Name" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-form-label">Email:</label>
|
||||
<br />
|
||||
<input type="email" class="form-control" asp-for="Input.Email" />
|
||||
<span asp-validation-for="Input.Email" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-form-label">Phone:</label>
|
||||
<br />
|
||||
<input type="tel" class="form-control" asp-for="Input.Phone" />
|
||||
<span asp-validation-for="Input.Phone" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-form-label">Chat Response OK?</label>
|
||||
<br />
|
||||
<input type="checkbox" checked="checked" asp-for="Input.ChatResponseOk" />
|
||||
<span asp-validation-for="Input.ChatResponseOk" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
input[type='checkbox'] {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@section Scripts {
|
||||
<partial name="_ValidationScriptsPartial" />
|
||||
}
|
||||
|
||||
}
|
||||
67
Server/Pages/GetSupport.cshtml.cs
Normal file
67
Server/Pages/GetSupport.cshtml.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Remotely.Server.Services;
|
||||
|
||||
namespace Remotely.Server.Pages
|
||||
{
|
||||
public class GetSupportModel : PageModel
|
||||
{
|
||||
public GetSupportModel(DataService dataService)
|
||||
{
|
||||
DataService = dataService;
|
||||
}
|
||||
|
||||
|
||||
private DataService DataService { get; }
|
||||
|
||||
[TempData]
|
||||
public string StatusMessage { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public InputModel Input { get; set; }
|
||||
|
||||
public IActionResult OnGet()
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPost(string deviceUuid)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
var orgID = DataService.GetDevice(deviceUuid)?.OrganizationID;
|
||||
|
||||
await DataService.AddAlert(new Remotely.Shared.Models.AlertOptions()
|
||||
{
|
||||
AlertDeviceID = deviceUuid,
|
||||
AlertMessage = $"{Input.Name} is requesting support. " +
|
||||
$"Email: {Input.Email}. " +
|
||||
$"Phone: {Input.Phone}. " +
|
||||
$"Chat OK: {Input.ChatResponseOk}.",
|
||||
ShouldAlert = true
|
||||
}, orgID);
|
||||
|
||||
StatusMessage = "We got it! Someone will contact you soon.";
|
||||
|
||||
return RedirectToPage("GetSupport", new { deviceUuid });
|
||||
}
|
||||
|
||||
public class InputModel
|
||||
{
|
||||
[StringLength(150)]
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string Phone { get; set; }
|
||||
public bool ChatResponseOk { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -19,7 +19,7 @@ using Microsoft.AspNetCore.HttpOverrides;
|
||||
using System.Net;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Remotely.Server.Auth;
|
||||
using Remotely.Server.Attributes;
|
||||
using Npgsql;
|
||||
|
||||
namespace Remotely.Server
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
using System.Security.Cryptography;
|
||||
using System;
|
||||
|
||||
namespace Remotely.Server.Auth
|
||||
namespace Remotely.Shared.Utilities
|
||||
{
|
||||
public static class PasswordGenerator
|
||||
{
|
||||
Loading…
Reference in New Issue
Block a user