mirror of
https://github.com/bitwarden/server.git
synced 2025-02-01 23:31:41 +01:00
remove mail and function projects
This commit is contained in:
parent
740453c900
commit
580e9e51e5
@ -27,8 +27,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Api", "src\Api\Api.csproj",
|
||||
EndProject
|
||||
Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "Sql", "src\Sql\Sql.sqlproj", "{58554E52-FDEC-4832-AFF9-302B01E08DCA}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mail", "util\Mail\Mail.csproj", "{B78A6C74-1A24-48C6-802A-13BE3E4DAFF1}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Billing", "src\Billing\Billing.csproj", "{02BC2982-ED8D-4A6D-A41E-092B3DAEB98A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity", "src\Identity\Identity.csproj", "{04148736-3C0B-445E-8B74-2020E7A53502}"
|
||||
@ -37,8 +35,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Setup", "util\Setup\Setup.c
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "util\Server\Server.csproj", "{66B0A682-658A-4A82-B606-A077A4871448}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Function", "util\Function\Function.csproj", "{A6C44A84-8E51-4C64-B9C4-7B7C23253345}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Icons", "src\Icons\Icons.csproj", "{9CF59342-3912-4B45-A2BA-0F173666586D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Events", "src\Events\Events.csproj", "{994DD611-F266-4BD3-8072-3B1B57267ED5}"
|
||||
@ -69,10 +65,6 @@ Global
|
||||
{58554E52-FDEC-4832-AFF9-302B01E08DCA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{58554E52-FDEC-4832-AFF9-302B01E08DCA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{58554E52-FDEC-4832-AFF9-302B01E08DCA}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{B78A6C74-1A24-48C6-802A-13BE3E4DAFF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B78A6C74-1A24-48C6-802A-13BE3E4DAFF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B78A6C74-1A24-48C6-802A-13BE3E4DAFF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B78A6C74-1A24-48C6-802A-13BE3E4DAFF1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{02BC2982-ED8D-4A6D-A41E-092B3DAEB98A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{02BC2982-ED8D-4A6D-A41E-092B3DAEB98A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{02BC2982-ED8D-4A6D-A41E-092B3DAEB98A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@ -89,10 +81,6 @@ Global
|
||||
{66B0A682-658A-4A82-B606-A077A4871448}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{66B0A682-658A-4A82-B606-A077A4871448}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{66B0A682-658A-4A82-B606-A077A4871448}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A6C44A84-8E51-4C64-B9C4-7B7C23253345}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A6C44A84-8E51-4C64-B9C4-7B7C23253345}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A6C44A84-8E51-4C64-B9C4-7B7C23253345}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A6C44A84-8E51-4C64-B9C4-7B7C23253345}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9CF59342-3912-4B45-A2BA-0F173666586D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9CF59342-3912-4B45-A2BA-0F173666586D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9CF59342-3912-4B45-A2BA-0F173666586D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@ -121,12 +109,10 @@ Global
|
||||
{3973D21B-A692-4B60-9B70-3631C057423A} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84D}
|
||||
{E8548AD6-7FB0-439A-8EB5-549A10336D2D} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84D}
|
||||
{58554E52-FDEC-4832-AFF9-302B01E08DCA} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84D}
|
||||
{B78A6C74-1A24-48C6-802A-13BE3E4DAFF1} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84E}
|
||||
{02BC2982-ED8D-4A6D-A41E-092B3DAEB98A} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84D}
|
||||
{04148736-3C0B-445E-8B74-2020E7A53502} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84D}
|
||||
{EF2164EF-1FC0-4518-A2ED-CE02D3630B00} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84E}
|
||||
{66B0A682-658A-4A82-B606-A077A4871448} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84E}
|
||||
{A6C44A84-8E51-4C64-B9C4-7B7C23253345} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84E}
|
||||
{9CF59342-3912-4B45-A2BA-0F173666586D} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84D}
|
||||
{994DD611-F266-4BD3-8072-3B1B57267ED5} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84D}
|
||||
{2235D24F-E607-47F4-81AD-BB4504ADF9C6} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84D}
|
||||
|
@ -1,70 +0,0 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Function.Models;
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Host;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Function
|
||||
{
|
||||
public static class BlockIp
|
||||
{
|
||||
[FunctionName("BlockIp")]
|
||||
public static void Run(
|
||||
[QueueTrigger("blockip", Connection = "")]string myQueueItem,
|
||||
out string outputQueueItem,
|
||||
TraceWriter log)
|
||||
{
|
||||
outputQueueItem = BlockIpAsync(myQueueItem).GetAwaiter().GetResult();
|
||||
log.Info($"C# Queue trigger function processed: {myQueueItem}, outputted: {outputQueueItem}");
|
||||
}
|
||||
|
||||
private static async Task<string> BlockIpAsync(string ipAddress)
|
||||
{
|
||||
var ipWhitelist = ConfigurationManager.AppSettings["WhitelistedIps"];
|
||||
if(ipWhitelist != null && ipWhitelist.Split(',').Contains(ipAddress))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var xAuthEmail = ConfigurationManager.AppSettings["X-Auth-Email"];
|
||||
var xAuthKey = ConfigurationManager.AppSettings["X-Auth-Key"];
|
||||
var zoneId = ConfigurationManager.AppSettings["ZoneId"];
|
||||
|
||||
using(var client = new HttpClient())
|
||||
{
|
||||
client.BaseAddress = new Uri("https://api.cloudflare.com");
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
client.DefaultRequestHeaders.Add("X-Auth-Email", xAuthEmail);
|
||||
client.DefaultRequestHeaders.Add("X-Auth-Key", xAuthKey);
|
||||
|
||||
var response = await client.PostAsJsonAsync(
|
||||
$"/client/v4/zones/{zoneId}/firewall/access_rules/rules",
|
||||
new
|
||||
{
|
||||
mode = "block",
|
||||
configuration = new
|
||||
{
|
||||
target = "ip",
|
||||
value = ipAddress
|
||||
},
|
||||
notes = $"Rate limit abuse on {DateTime.UtcNow.ToString()}."
|
||||
});
|
||||
|
||||
var responseString = await response.Content.ReadAsStringAsync();
|
||||
var responseJson = JsonConvert.DeserializeObject<AccessRuleResponse>(responseString);
|
||||
|
||||
if(!responseJson.Success)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Uncomment whenever we can delay the returned message. Functions do not support that at this time.
|
||||
return null; //responseJson.Result?.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Host;
|
||||
|
||||
namespace Bit.Function
|
||||
{
|
||||
public static class DatabaseMaintenance
|
||||
{
|
||||
[FunctionName("DatabaseMaintenance")]
|
||||
public static void Run([TimerTrigger("0 0 4 * * *")]TimerInfo myTimer, TraceWriter log)
|
||||
{
|
||||
var connectionString = ConfigurationManager.ConnectionStrings["Vault"].ConnectionString;
|
||||
using(var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
// ref: http://bit.ly/2zFNcZo
|
||||
var cmd = new SqlCommand("[dbo].[AzureSQLMaintenance]", connection)
|
||||
{
|
||||
CommandType = CommandType.StoredProcedure
|
||||
};
|
||||
|
||||
// Options: "all", "index", "statistics"
|
||||
cmd.Parameters.Add("@operation", SqlDbType.NVarChar).Value = "all";
|
||||
// Options: "smart", "dummy"
|
||||
cmd.Parameters.Add("@mode", SqlDbType.NVarChar).Value = "smart";
|
||||
// Options: 0, 1
|
||||
cmd.Parameters.Add("@LogToTable", SqlDbType.Bit).Value = 1;
|
||||
|
||||
// Asynchronous BeginExecuteNonQuery for this long running sproc to avoid timeouts
|
||||
var result = cmd.BeginExecuteNonQuery();
|
||||
cmd.EndExecuteNonQuery(result);
|
||||
|
||||
log.Info($"Started [dbo].[AzureSQLMaintenance] at {DateTime.UtcNow}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,175 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Extensions.Http;
|
||||
using Microsoft.Azure.WebJobs.Host;
|
||||
|
||||
namespace Bit.Function
|
||||
{
|
||||
public static class Download
|
||||
{
|
||||
// Desktop
|
||||
const string DesktopCurrentVersion = "0.0.7";
|
||||
|
||||
const string DesktopWindowsPortableFileName = "Bitwarden-Portable-{0}.exe";
|
||||
const string DesktopWindowsWebInstallerFileName = "Bitwarden-Installer-{0}.exe";
|
||||
const string DesktopWindowsAppxFileName = "Bitwarden-{0}.appx";
|
||||
const string DesktopWindowsAppx32FileName = "Bitwarden-{0}-ia32.appx";
|
||||
const string DesktopWindowsStoreUrl = "https://www.microsoft.com/en-us/store/b/home";
|
||||
const string DesktopWindowsChocoUrl = "https://chocolatey.org/packages/bitwarden";
|
||||
|
||||
const string DesktopMacOsDmgFileName = "Bitwarden-{0}.dmg";
|
||||
const string DesktopMacOsPkgFileName = "Bitwarden-{0}.pkg";
|
||||
const string DesktopMacOsZipFileName = "bitwarden-{0}-mac.zip";
|
||||
const string DesktopMacOsStoreUrl = "https://itunes.com";
|
||||
const string DesktopMacOsCaskUrl = "https://caskroom.github.io/search";
|
||||
|
||||
const string DesktopLinuxAppImageFileName = "Bitwarden-{0}-x86_64.AppImage";
|
||||
const string DesktopLinuxDebFileName = "Bitwarden-{0}-amd64.deb";
|
||||
const string DesktopLinuxRpmFileName = "Bitwarden-{0}-x86_64.rpm";
|
||||
const string DesktopLinuxFreeBsdFileName = "Bitwarden-{0}.freebsd";
|
||||
const string DesktopLinuxSnapUrl = "https://snapcraft.io/";
|
||||
|
||||
// Browser
|
||||
const string BrowserSafariFileUrl = "https://cdn.bitwarden.com/safari-extension/bitwarden-1.24.1.safariextz";
|
||||
const string BrowserSafariStoreUrl = "https://safari-extensions.apple.com";
|
||||
|
||||
[FunctionName("Download")]
|
||||
public static HttpResponseMessage Run(
|
||||
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "api/download")]HttpRequestMessage req,
|
||||
TraceWriter log)
|
||||
{
|
||||
var qs = req.GetQueryNameValuePairs();
|
||||
var app = GetQsParam(qs, "app")?.ToLowerInvariant();
|
||||
var platform = GetQsParam(qs, "platform")?.ToLowerInvariant();
|
||||
var variant = GetQsParam(qs, "variant")?.ToLowerInvariant();
|
||||
|
||||
if(string.IsNullOrWhiteSpace(app))
|
||||
{
|
||||
return req.CreateResponse(HttpStatusCode.BadRequest, "'app' parameter is required.");
|
||||
}
|
||||
|
||||
if(string.IsNullOrWhiteSpace(platform))
|
||||
{
|
||||
return req.CreateResponse(HttpStatusCode.BadRequest, "'platform' parameter is required.");
|
||||
}
|
||||
|
||||
if(app == "desktop")
|
||||
{
|
||||
if(platform == "windows")
|
||||
{
|
||||
if(variant == null || variant == "exe" || variant == "web")
|
||||
{
|
||||
return GetDesktopDownloadResponse(req, DesktopWindowsWebInstallerFileName);
|
||||
}
|
||||
else if(variant == "portable")
|
||||
{
|
||||
return GetDesktopDownloadResponse(req, DesktopWindowsPortableFileName);
|
||||
}
|
||||
else if(variant == "appx")
|
||||
{
|
||||
return GetDesktopDownloadResponse(req, DesktopWindowsAppxFileName);
|
||||
}
|
||||
else if(variant == "appx32")
|
||||
{
|
||||
return GetDesktopDownloadResponse(req, DesktopWindowsAppx32FileName);
|
||||
}
|
||||
else if(variant == "store")
|
||||
{
|
||||
return GetRedirectResponse(req, DesktopWindowsStoreUrl);
|
||||
}
|
||||
else if(variant == "choco")
|
||||
{
|
||||
return GetRedirectResponse(req, DesktopWindowsChocoUrl);
|
||||
}
|
||||
}
|
||||
else if(platform == "mac" || platform == "macos")
|
||||
{
|
||||
if(variant == null || variant == "dmg")
|
||||
{
|
||||
return GetDesktopDownloadResponse(req, DesktopMacOsDmgFileName);
|
||||
}
|
||||
else if(variant == "pkg")
|
||||
{
|
||||
return GetDesktopDownloadResponse(req, DesktopMacOsPkgFileName);
|
||||
}
|
||||
else if(variant == "zip")
|
||||
{
|
||||
return GetDesktopDownloadResponse(req, DesktopMacOsZipFileName);
|
||||
}
|
||||
else if(variant == "store")
|
||||
{
|
||||
return GetRedirectResponse(req, DesktopMacOsStoreUrl);
|
||||
}
|
||||
else if(variant == "cask" || variant == "brew")
|
||||
{
|
||||
return GetRedirectResponse(req, DesktopMacOsCaskUrl);
|
||||
}
|
||||
}
|
||||
else if(platform == "linux")
|
||||
{
|
||||
if(variant == null || variant == "appimage")
|
||||
{
|
||||
return GetDesktopDownloadResponse(req, DesktopLinuxAppImageFileName);
|
||||
}
|
||||
else if(variant == "deb")
|
||||
{
|
||||
return GetDesktopDownloadResponse(req, DesktopLinuxDebFileName);
|
||||
}
|
||||
else if(variant == "rpm")
|
||||
{
|
||||
return GetDesktopDownloadResponse(req, DesktopLinuxRpmFileName);
|
||||
}
|
||||
else if(variant == "freebsd")
|
||||
{
|
||||
return GetDesktopDownloadResponse(req, DesktopLinuxFreeBsdFileName);
|
||||
}
|
||||
else if(variant == "snap")
|
||||
{
|
||||
return GetRedirectResponse(req, DesktopLinuxSnapUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(app == "browser")
|
||||
{
|
||||
if(platform == "safari")
|
||||
{
|
||||
if(variant == null || variant == "safariextz")
|
||||
{
|
||||
return GetRedirectResponse(req, BrowserSafariFileUrl);
|
||||
}
|
||||
else if(variant == "store")
|
||||
{
|
||||
return GetRedirectResponse(req, BrowserSafariStoreUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return req.CreateResponse(HttpStatusCode.NotFound, "Download not found.");
|
||||
}
|
||||
|
||||
private static string GetQsParam(IEnumerable<KeyValuePair<string, string>> qs, string key)
|
||||
{
|
||||
return qs.FirstOrDefault(q => string.Compare(q.Key, key, true) == 0).Value;
|
||||
}
|
||||
|
||||
private static HttpResponseMessage GetDesktopDownloadResponse(HttpRequestMessage req, string filename)
|
||||
{
|
||||
var filenameWithVersion = string.Format(filename, DesktopCurrentVersion);
|
||||
var downloadUrl = string.Format("https://github.com/bitwarden/desktop/releases/download/v{0}/{1}",
|
||||
DesktopCurrentVersion, filenameWithVersion);
|
||||
return GetRedirectResponse(req, downloadUrl);
|
||||
}
|
||||
|
||||
private static HttpResponseMessage GetRedirectResponse(HttpRequestMessage req, string url)
|
||||
{
|
||||
var response = req.CreateResponse(HttpStatusCode.Redirect);
|
||||
response.Headers.Location = new Uri(url);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net471</TargetFramework>
|
||||
<RootNamespace>Bit.Function</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.14" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Configuration" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="host.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="local.settings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -1,15 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Host;
|
||||
|
||||
namespace Bit.Function
|
||||
{
|
||||
public static class KeepAlive
|
||||
{
|
||||
[FunctionName("KeepAlive")]
|
||||
public static void Run([TimerTrigger("0 */15 * * * *")]TimerInfo myTimer, TraceWriter log)
|
||||
{
|
||||
log.Info($"C# Timer trigger function executed at: {DateTime.Now}");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
namespace Bit.Function.Models
|
||||
{
|
||||
public class AccessRuleResponse
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public AccessRuleResultResponse Result { get; set; }
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
namespace Bit.Function.Models
|
||||
{
|
||||
public class AccessRuleResultResponse
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public ConfigurationResponse Configuration { get; set; }
|
||||
|
||||
public class ConfigurationResponse
|
||||
{
|
||||
public string Target { get; set; }
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Bit.Function.Models
|
||||
{
|
||||
public class ListResult
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public List<AccessRuleResultResponse> Result { get; set; }
|
||||
}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Mail;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Extensions.Http;
|
||||
using Microsoft.Azure.WebJobs.Host;
|
||||
|
||||
namespace Bit.Function
|
||||
{
|
||||
public static class NewHelpdeskTicket
|
||||
{
|
||||
[FunctionName("NewHelpdeskTicket")]
|
||||
public static HttpResponseMessage Run(
|
||||
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "api/newhelpdeskticket")]HttpRequestMessage req,
|
||||
TraceWriter log)
|
||||
{
|
||||
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls |
|
||||
// SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
|
||||
|
||||
var data = req.Content.ReadAsFormDataAsync().Result;
|
||||
if(data == null)
|
||||
{
|
||||
return req.CreateResponse(HttpStatusCode.BadRequest, "No data provided.");
|
||||
}
|
||||
|
||||
if(string.IsNullOrWhiteSpace(data["name"]))
|
||||
{
|
||||
return req.CreateResponse(HttpStatusCode.BadRequest, "Name is required.");
|
||||
}
|
||||
|
||||
if(data["name"].Length > 50)
|
||||
{
|
||||
return req.CreateResponse(HttpStatusCode.BadRequest, "Name must be less than 50 characters.");
|
||||
}
|
||||
|
||||
if(string.IsNullOrWhiteSpace(data["email"]))
|
||||
{
|
||||
return req.CreateResponse(HttpStatusCode.BadRequest, "Email is required.");
|
||||
}
|
||||
|
||||
if(data["email"].Length > 50)
|
||||
{
|
||||
return req.CreateResponse(HttpStatusCode.BadRequest, "Email must be less than 50 characters.");
|
||||
}
|
||||
|
||||
if(!data["email"].Contains("@") || !data["email"].Contains("."))
|
||||
{
|
||||
return req.CreateResponse(HttpStatusCode.BadRequest, "Email is not valid.");
|
||||
}
|
||||
|
||||
if(string.IsNullOrWhiteSpace(data["message"]))
|
||||
{
|
||||
return req.CreateResponse(HttpStatusCode.BadRequest, "Message is required.");
|
||||
}
|
||||
|
||||
//if(!await SubmitApiAsync(data["name"], data["email"], data["message"], log))
|
||||
//{
|
||||
// return req.CreateResponse(HttpStatusCode.BadRequest, "Ticket failed to create.");
|
||||
//}
|
||||
|
||||
SubmitEmail(data["name"], data["email"], data["message"], log);
|
||||
|
||||
return req.CreateResponse(HttpStatusCode.OK, "Ticket created.");
|
||||
}
|
||||
|
||||
private async static Task<bool> SubmitApiAsync(string name, string email, string message, TraceWriter log)
|
||||
{
|
||||
using(var client = new HttpClient())
|
||||
{
|
||||
client.BaseAddress = new Uri("https://bitwarden.freshdesk.com/api/v2");
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
client.DefaultRequestHeaders.Add("Authorization", MakeFreshdeskApiAuthHeader(log));
|
||||
|
||||
var response = await client.PostAsJsonAsync("tickets",
|
||||
new
|
||||
{
|
||||
name = name,
|
||||
email = email,
|
||||
status = 2,
|
||||
priority = 2,
|
||||
source = 1,
|
||||
subject = "Bitwarden.com Website Contact",
|
||||
description = FormatMessage(message)
|
||||
});
|
||||
|
||||
return response.IsSuccessStatusCode;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SubmitEmail(string name, string email, string message, TraceWriter log)
|
||||
{
|
||||
var sendgridApiKey = ConfigurationManager.AppSettings["SendgridApiKey"];
|
||||
var client = new SmtpClient("smtp.sendgrid.net", /*465*/ 587)
|
||||
{
|
||||
//EnableSsl = true,
|
||||
Credentials = new NetworkCredential("apikey", sendgridApiKey)
|
||||
};
|
||||
|
||||
var fromAddress = new MailAddress(email, name, Encoding.UTF8);
|
||||
var mailMessage = new MailMessage(fromAddress, new MailAddress("bitwardencomsupport@bitwarden.freshdesk.com"))
|
||||
{
|
||||
Subject = "Bitwarden.com Website Contact",
|
||||
Body = FormatMessage(message),
|
||||
IsBodyHtml = true
|
||||
};
|
||||
|
||||
client.SendCompleted += (s, e) =>
|
||||
{
|
||||
client.Dispose();
|
||||
mailMessage.Dispose();
|
||||
};
|
||||
client.SendAsync(mailMessage, null);
|
||||
}
|
||||
|
||||
private static string FormatMessage(string message)
|
||||
{
|
||||
return message.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", "<br>");
|
||||
}
|
||||
|
||||
private static string MakeFreshdeskApiAuthHeader(TraceWriter log)
|
||||
{
|
||||
var freshdeskApiKey = ConfigurationManager.AppSettings["FreshdeskApiKey"];
|
||||
var b64Creds = Convert.ToBase64String(
|
||||
Encoding.GetEncoding("ISO-8859-1").GetBytes(freshdeskApiKey + ":X"));
|
||||
return b64Creds;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Function.Models;
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Host;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Function
|
||||
{
|
||||
public static class UnblockIp
|
||||
{
|
||||
[FunctionName("UnblockIp")]
|
||||
public static void Run(
|
||||
[QueueTrigger("unblockip", Connection = "")]string myQueueItem,
|
||||
TraceWriter log)
|
||||
{
|
||||
log.Info($"C# Queue trigger function processed: {myQueueItem}");
|
||||
UnblockIpAsync(myQueueItem, log).Wait();
|
||||
}
|
||||
|
||||
private static async Task UnblockIpAsync(string id, TraceWriter log)
|
||||
{
|
||||
if(id == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var zoneId = ConfigurationManager.AppSettings["ZoneId"];
|
||||
var xAuthEmail = ConfigurationManager.AppSettings["X-Auth-Email"];
|
||||
var xAuthKey = ConfigurationManager.AppSettings["X-Auth-Key"];
|
||||
|
||||
if(id.Contains(".") || id.Contains(":"))
|
||||
{
|
||||
// IP address messages.
|
||||
using(var client = new HttpClient())
|
||||
{
|
||||
client.BaseAddress = new Uri("https://api.cloudflare.com");
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
client.DefaultRequestHeaders.Add("X-Auth-Email", xAuthEmail);
|
||||
client.DefaultRequestHeaders.Add("X-Auth-Key", xAuthKey);
|
||||
|
||||
var response = await client.GetAsync($"/client/v4/zones/{zoneId}/firewall/access_rules/rules?" +
|
||||
$"configuration_target=ip&configuration_value={id}");
|
||||
|
||||
var responseString = await response.Content.ReadAsStringAsync();
|
||||
var responseJson = JsonConvert.DeserializeObject<ListResult>(responseString);
|
||||
|
||||
if(!responseJson.Success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach(var rule in responseJson.Result)
|
||||
{
|
||||
if(rule.Configuration?.Value != id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
log.Info($"Unblock IP {id}, {rule.Id}");
|
||||
await DeleteRuleAsync(zoneId, xAuthEmail, xAuthKey, rule.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Info($"Unblock Id {id}");
|
||||
await DeleteRuleAsync(zoneId, xAuthEmail, xAuthKey, id);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task DeleteRuleAsync(string zoneId, string xAuthEmail, string xAuthKey, string id)
|
||||
{
|
||||
var path = $"/client/v4/zones/{zoneId}/firewall/access_rules/rules/{id}";
|
||||
using(var client = new HttpClient())
|
||||
{
|
||||
client.BaseAddress = new Uri("https://api.cloudflare.com");
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
client.DefaultRequestHeaders.Add("X-Auth-Email", xAuthEmail);
|
||||
client.DefaultRequestHeaders.Add("X-Auth-Key", xAuthKey);
|
||||
await client.DeleteAsync(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
{
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"IsEncrypted": false,
|
||||
"Values": {
|
||||
"AzureWebJobsStorage": "SECRET",
|
||||
"AzureWebJobsDashboard": "SECRET"
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<RootNamespace>Bit.Mail</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="wwwroot\**\*">
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,17 +0,0 @@
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
||||
namespace Bit.Mail
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
WebHost
|
||||
.CreateDefaultBuilder(args)
|
||||
.UseStartup<Startup>()
|
||||
.Build()
|
||||
.Run();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:33104/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Mail": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "http://localhost:5004",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Bit.Mail
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services) { }
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseFileServer();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/// <binding BeforeBuild='build, dist' Clean='clean' ProjectOpened='build. dist' />
|
||||
|
||||
var gulp = require('gulp'),
|
||||
rimraf = require('rimraf'),
|
||||
premailer = require('gulp-premailer');
|
||||
|
||||
var paths = {
|
||||
dist: '../../mail_dist/',
|
||||
wwwroot: './wwwroot/'
|
||||
};
|
||||
|
||||
gulp.task('inline', ['clean'], function () {
|
||||
return gulp.src(paths.wwwroot + 'templates/*.html')
|
||||
.pipe(premailer())
|
||||
.pipe(gulp.dest(paths.dist));
|
||||
});
|
||||
|
||||
gulp.task('clean', function (cb) {
|
||||
return rimraf(paths.dist, cb);
|
||||
});
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"name": "bitwarden",
|
||||
"version": "0.0.0",
|
||||
"devDependencies": {
|
||||
"gulp": "3.9.1",
|
||||
"rimraf": "2.5.4",
|
||||
"gulp-premailer": "0.4.0"
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<!--
|
||||
Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
|
||||
-->
|
||||
<system.webServer>
|
||||
<handlers>
|
||||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
|
||||
</handlers>
|
||||
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" startupTimeLimit="3600" requestTimeout="23:00:00" />
|
||||
</system.webServer>
|
||||
<appSettings>
|
||||
<add key="vs:EnableBrowserLink" value="true" />
|
||||
</appSettings>
|
||||
<system.web>
|
||||
<compilation debug="true"></compilation>
|
||||
</system.web>
|
||||
</configuration>
|
@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Bitwarden Mail Templates</title>
|
||||
</head>
|
||||
<body>
|
||||
<ol>
|
||||
<li><a href="templates/welcome.html">Welcome</a></li>
|
||||
<li><a href="templates/announcement.html">Announcement</a></li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
@ -1,282 +0,0 @@
|
||||
/* -------------------------------------
|
||||
GLOBAL
|
||||
A very basic CSS reset
|
||||
------------------------------------- */
|
||||
body, html, body * {
|
||||
margin: 0;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
box-sizing: border-box;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
line-height: 25px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-size-adjust: none;
|
||||
width: 100% !important;
|
||||
height: 100%;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
/* Let's make sure all tables have defaults */
|
||||
table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table td.middle {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
BODY & CONTAINER
|
||||
------------------------------------- */
|
||||
body {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.body-wrap {
|
||||
background-color: #f6f6f6;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.container, .container-table {
|
||||
width: 600px;
|
||||
max-width: 600px !important;
|
||||
display: block !important;
|
||||
/* makes it centered */
|
||||
clear: both !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
.content {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.content-banner {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
LOGO, HEADER, FOOTER, MAIN
|
||||
------------------------------------- */
|
||||
.logo {
|
||||
padding: 20px 0 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.banner, .banner img {
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.main {
|
||||
background-color: white;
|
||||
border: 1px solid #e9e9e9;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.content-banner .main {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.content-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.content-block {
|
||||
padding: 0 0 10px;
|
||||
}
|
||||
|
||||
.content-block img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.content-block-spaced {
|
||||
padding: 0 0 25px;
|
||||
}
|
||||
|
||||
.indented {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.li {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
width: 100%;
|
||||
clear: both;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.footer, .footer p, .footer a, .footer td, .footer br {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.footer .social-icons table {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.footer .social-icons td {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
TYPOGRAPHY
|
||||
------------------------------------- */
|
||||
.h3 {
|
||||
font-size: 18px;
|
||||
line-height: 25px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.biglink a {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
LINKS & BUTTONS
|
||||
------------------------------------- */
|
||||
a {
|
||||
color: #3c8dbc;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
background-color: #3c8dbc;
|
||||
border: solid #3c8dbc;
|
||||
border-width: 10px 20px;
|
||||
line-height: 2em;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
border-radius: 5px;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
OTHER STYLES THAT MIGHT BE USEFUL
|
||||
------------------------------------- */
|
||||
.last {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.first {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.aligncenter {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.alignright {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.alignleft {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
ALERTS
|
||||
Change the class depending on warning email, good email or bad email
|
||||
------------------------------------- */
|
||||
.alert {
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
.alert a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.alert.alert-warning {
|
||||
background-color: #FF9F00;
|
||||
}
|
||||
|
||||
.alert.alert-bad {
|
||||
background-color: #D0021B;
|
||||
}
|
||||
|
||||
.alert.alert-good {
|
||||
background-color: #68B90F;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
RESPONSIVE AND MOBILE FRIENDLY STYLES
|
||||
------------------------------------- */
|
||||
@media only screen and (max-width: 600px) {
|
||||
body {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.container, .container-table {
|
||||
padding: 0 !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 0 0 10px 0 !important;
|
||||
}
|
||||
|
||||
.content-wrap {
|
||||
padding: 10px !important;
|
||||
}
|
||||
|
||||
.invoice {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.main {
|
||||
border-right: none !important;
|
||||
border-left: none !important;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.logo {
|
||||
padding-top: 10px !important;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 10px !important;
|
||||
}
|
||||
|
||||
.indented {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Announcement</title>
|
||||
<link href="../styles.css" media="all" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<table class="body-wrap" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="container" align="center">
|
||||
<table cellpadding="0" cellspacing="0" class="container-table">
|
||||
<tr>
|
||||
<td class="content content-banner" align="center">
|
||||
<a href="#" title="" target="_blank" class="banner">
|
||||
<img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=Announcement%20Image&w=600&h=158"
|
||||
width="600" alt="" />
|
||||
</a>
|
||||
<table class="main" width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="content-wrap">
|
||||
<table width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="h3 content-block">
|
||||
A title!
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
Some text about an announcement.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block indented">
|
||||
<table width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td width="15">•</td>
|
||||
<td class="li">Bullet 1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>•</td>
|
||||
<td class="li">Bullet 2</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block last">
|
||||
Thank you!<br />
|
||||
The Bitwarden Team
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="footer" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td class="aligncenter content-block">
|
||||
8bit Solutions LLC<br />
|
||||
You can <a href="[unsubscribe]">unsubscribe</a> from future mailings.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="aligncenter social-icons" align="center">
|
||||
<table cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td><a href="https://twitter.com/bitwarden_app" target="_blank"><img src="https://bitwarden.com/images/mail-twitter.png" alt="Twitter" width="30" height="30" /></a></td>
|
||||
<td><a href="https://www.facebook.com/bitwarden/" target="_blank"><img src="https://bitwarden.com/images/mail-facebook.png" alt="Facebook" width="30" height="30" /></a></td>
|
||||
<td><a href="https://plus.google.com/+bitwarden" target="_blank"><img src="https://bitwarden.com/images/mail-gplus.png" alt="Google+" width="30" height="30" /></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
@ -1,146 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Welcome</title>
|
||||
<link href="../styles.css" media="all" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<table class="body-wrap" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td valign="middle" class="aligncenter middle logo">
|
||||
<img src="https://bitwarden.com/images/logo-gray.png" alt="" width="250" height="39" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="container" align="center">
|
||||
<table cellpadding="0" cellspacing="0" class="container-table">
|
||||
<tr>
|
||||
<td class="content" align="center">
|
||||
<table class="main" width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="content-wrap">
|
||||
<table width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
Thank you for creating an account with Bitwarden. You may now log in with your new account.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
Did you know that Bitwarden is free to sync with all of your devices? Download Bitwarden today on:
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="h3">
|
||||
Desktop
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
Access Bitwarden on Windows, macOS, and Linux desktops with our native desktop application.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
<a href="https://bitwarden.com/#download" target="_blank">
|
||||
<img src="https://bitwarden.com/images/mail-os.png" alt="Windows, macOS, and Linux" width="550" height="110" />
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="h3">
|
||||
Web Browser
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
Integrate Bitwarden directly into your favorite browser. Use our browser extensions for a seamless browsing experience.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
<a href="https://bitwarden.com/#download-browser" target="_blank">
|
||||
<img src="https://bitwarden.com/images/mail-browsers.png" alt="Chrome, Firefox, Opera, Edge, Safari, and more" width="550" height="90" />
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="h3">
|
||||
Mobile
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
Take Bitwarden on the go with our mobile apps for your phone or tablet device.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
<a href="https://bitwarden.com/#download-mobile" target="_blank">
|
||||
<img src="https://bitwarden.com/images/mail-stores.png" alt="App Store and Google Play" width="550" height="85" />
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="h3">
|
||||
Web
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Stuck without any of your devices? Using a friend's computer? You can access your Bitwarden vault from any web enabled device by using the web vault.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block h3 biglink">
|
||||
<a target="_blank" href="https://vault.bitwarden.com/?utm_source=welcome_email&utm_medium=email">vault.bitwarden.com</a>
|
||||
<br />
|
||||
<br />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
If you have any questions or problems you can email us from our website at <a target="_blank" href="https://bitwarden.com/contact/?utm_source=welcome_email&utm_medium=email">https://bitwarden.com/contact</a>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block last">
|
||||
Thank you!<br />
|
||||
The Bitwarden Team
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="footer" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td class="aligncenter content-block">
|
||||
8bit Solutions LLC
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="aligncenter social-icons" align="center">
|
||||
<table cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td><a href="https://twitter.com/bitwarden_app" target="_blank"><img src="https://bitwarden.com/images/mail-twitter.png" alt="Twitter" width="30" height="30" /></a></td>
|
||||
<td><a href="https://www.facebook.com/bitwarden/" target="_blank"><img src="https://bitwarden.com/images/mail-facebook.png" alt="Facebook" width="30" height="30" /></a></td>
|
||||
<td><a href="https://plus.google.com/+bitwarden" target="_blank"><img src="https://bitwarden.com/images/mail-gplus.png" alt="Google+" width="30" height="30" /></a></td>
|
||||
<td><a href="https://github.com/bitwarden" target="_blank"><img src="https://bitwarden.com/images/mail-github.png" alt="GitHub" width="30" height="30" /></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user