global: add null safety checks
This commit is contained in:
@@ -43,7 +43,7 @@ namespace Notesnook.API.Authorization
|
||||
PathString path = context.Resource is DefaultHttpContext httpContext ? httpContext.Request.Path : null;
|
||||
var result = this.IsAuthorized(context.User, path);
|
||||
if (result.Succeeded) context.Succeed(requirement);
|
||||
else if (result.AuthorizationFailure.FailureReasons.Any())
|
||||
else if (result.AuthorizationFailure?.FailureReasons.Any() == true)
|
||||
context.Fail(result.AuthorizationFailure.FailureReasons.First());
|
||||
else context.Fail();
|
||||
|
||||
@@ -63,11 +63,11 @@ namespace Notesnook.API.Authorization
|
||||
return PolicyAuthorizationResult.Forbid(AuthorizationFailure.Failed(reason));
|
||||
}
|
||||
|
||||
var hasSyncScope = User.HasClaim("scope", "notesnook.sync");
|
||||
var isInAudience = User.HasClaim("aud", "notesnook");
|
||||
var hasRole = User.HasClaim("role", "notesnook");
|
||||
var hasSyncScope = User?.HasClaim("scope", "notesnook.sync") ?? false;
|
||||
var isInAudience = User?.HasClaim("aud", "notesnook") ?? false;
|
||||
var hasRole = User?.HasClaim("role", "notesnook") ?? false;
|
||||
|
||||
var isEmailVerified = User.HasClaim("verified", "true");
|
||||
var isEmailVerified = User?.HasClaim("verified", "true") ?? false;
|
||||
|
||||
if (!isEmailVerified)
|
||||
{
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Notesnook.API.Controllers
|
||||
if (item.Type != "callToActions") continue;
|
||||
foreach (var action in item.Actions)
|
||||
{
|
||||
if (action.Type != "link") continue;
|
||||
if (action.Type != "link" || action.Data == null) continue;
|
||||
|
||||
action.Data = action.Data.Replace("{{UserId}}", userId ?? "0");
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Notesnook.API.Controllers
|
||||
[Authorize(Policy = "Notesnook")]
|
||||
public async Task<IActionResult> GetApiKeysAsync()
|
||||
{
|
||||
var userId = User.FindFirstValue("sub");
|
||||
var userId = User.GetUserId();
|
||||
try
|
||||
{
|
||||
var apiKeys = await inboxApiKeysRepository.FindAsync(t => t.UserId == userId);
|
||||
@@ -64,7 +64,7 @@ namespace Notesnook.API.Controllers
|
||||
[Authorize(Policy = "Notesnook")]
|
||||
public async Task<IActionResult> CreateApiKeyAsync([FromBody] InboxApiKey request)
|
||||
{
|
||||
var userId = User.FindFirstValue("sub");
|
||||
var userId = User.GetUserId();
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(request.Name))
|
||||
@@ -104,7 +104,7 @@ namespace Notesnook.API.Controllers
|
||||
[Authorize(Policy = "Notesnook")]
|
||||
public async Task<IActionResult> DeleteApiKeyAsync(string apiKey)
|
||||
{
|
||||
var userId = User.FindFirstValue("sub");
|
||||
var userId = User.GetUserId();
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(apiKey))
|
||||
@@ -126,7 +126,7 @@ namespace Notesnook.API.Controllers
|
||||
[Authorize(Policy = InboxApiKeyAuthenticationDefaults.AuthenticationScheme)]
|
||||
public async Task<IActionResult> GetPublicKeyAsync()
|
||||
{
|
||||
var userId = User.FindFirstValue("sub");
|
||||
var userId = User.GetUserId();
|
||||
try
|
||||
{
|
||||
var userSetting = await userSettingsRepository.FindOneAsync(u => u.UserId == userId);
|
||||
@@ -147,7 +147,7 @@ namespace Notesnook.API.Controllers
|
||||
[Authorize(Policy = InboxApiKeyAuthenticationDefaults.AuthenticationScheme)]
|
||||
public async Task<IActionResult> CreateInboxItemAsync([FromBody] InboxSyncItem request)
|
||||
{
|
||||
var userId = User.FindFirstValue("sub");
|
||||
var userId = User.GetUserId();
|
||||
try
|
||||
{
|
||||
if (request.Key.Algorithm != Algorithms.XSAL_X25519_7)
|
||||
|
||||
@@ -98,9 +98,8 @@ namespace Notesnook.API.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
var userId = this.User.FindFirstValue("sub");
|
||||
var userId = this.User.GetUserId();
|
||||
var jti = this.User.FindFirstValue("jti");
|
||||
if (userId == null) return Unauthorized();
|
||||
|
||||
var existingMonograph = await FindMonographAsync(userId, monograph);
|
||||
if (existingMonograph != null && !existingMonograph.Deleted) return await UpdateAsync(deviceId, monograph);
|
||||
@@ -144,9 +143,8 @@ namespace Notesnook.API.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
var userId = this.User.FindFirstValue("sub");
|
||||
var userId = this.User.GetUserId();
|
||||
var jti = this.User.FindFirstValue("jti");
|
||||
if (userId == null) return Unauthorized();
|
||||
|
||||
var existingMonograph = await FindMonographAsync(userId, monograph);
|
||||
if (existingMonograph == null || existingMonograph.Deleted)
|
||||
@@ -193,8 +191,7 @@ namespace Notesnook.API.Controllers
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetUserMonographsAsync()
|
||||
{
|
||||
var userId = this.User.FindFirstValue("sub");
|
||||
if (userId == null) return Unauthorized();
|
||||
var userId = this.User.GetUserId();
|
||||
|
||||
var userMonographs = (await monographs.Collection.FindAsync(
|
||||
Builders<Monograph>.Filter.And(
|
||||
@@ -257,8 +254,7 @@ namespace Notesnook.API.Controllers
|
||||
[HttpDelete("{id}")]
|
||||
public async Task<IActionResult> DeleteAsync([FromQuery] string? deviceId, [FromRoute] string id)
|
||||
{
|
||||
var userId = this.User.FindFirstValue("sub");
|
||||
if (userId is null) return Unauthorized();
|
||||
var userId = this.User.GetUserId();
|
||||
|
||||
var monograph = await FindMonographAsync(id);
|
||||
if (monograph == null || monograph.Deleted)
|
||||
@@ -310,12 +306,13 @@ namespace Notesnook.API.Controllers
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<string> CleanupContentAsync(ClaimsPrincipal user, string content)
|
||||
private async Task<string> CleanupContentAsync(ClaimsPrincipal user, string? content)
|
||||
{
|
||||
if (string.IsNullOrEmpty(content)) return string.Empty;
|
||||
if (Constants.IS_SELF_HOSTED) return content;
|
||||
try
|
||||
{
|
||||
var json = JsonSerializer.Deserialize<MonographContent>(content);
|
||||
var json = JsonSerializer.Deserialize<MonographContent>(content) ?? throw new Exception("Invalid monograph content.");
|
||||
var html = json.Data;
|
||||
|
||||
if (user.IsUserSubscribed())
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Notesnook.API.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
var userId = this.User.FindFirstValue("sub") ?? throw new Exception("User not found.");
|
||||
var userId = this.User.GetUserId();
|
||||
new SyncDeviceService(new SyncDevice(userId, deviceId)).RegisterDevice();
|
||||
return Ok();
|
||||
}
|
||||
@@ -61,7 +61,7 @@ namespace Notesnook.API.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
var userId = this.User.FindFirstValue("sub") ?? throw new Exception("User not found.");
|
||||
var userId = this.User.GetUserId();
|
||||
new SyncDeviceService(new SyncDevice(userId, deviceId)).UnregisterDevice();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Notesnook.API.Controllers
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetUser()
|
||||
{
|
||||
var userId = User.FindFirstValue("sub");
|
||||
var userId = User.GetUserId();
|
||||
try
|
||||
{
|
||||
UserResponse response = await UserService.GetUserAsync(userId);
|
||||
@@ -72,7 +72,7 @@ namespace Notesnook.API.Controllers
|
||||
[HttpPatch]
|
||||
public async Task<IActionResult> UpdateUser([FromBody] UserKeys keys)
|
||||
{
|
||||
var userId = User.FindFirstValue("sub");
|
||||
var userId = User.GetUserId();
|
||||
try
|
||||
{
|
||||
await UserService.SetUserKeysAsync(userId, keys);
|
||||
@@ -88,7 +88,7 @@ namespace Notesnook.API.Controllers
|
||||
[HttpPost("reset")]
|
||||
public async Task<IActionResult> Reset([FromForm] bool removeAttachments)
|
||||
{
|
||||
var userId = this.User.FindFirstValue("sub");
|
||||
var userId = this.User.GetUserId();
|
||||
|
||||
if (await UserService.ResetUserAsync(userId, removeAttachments))
|
||||
return Ok();
|
||||
@@ -99,7 +99,7 @@ namespace Notesnook.API.Controllers
|
||||
[RequestTimeout(5 * 60 * 1000)]
|
||||
public async Task<IActionResult> Delete([FromForm] DeleteAccountForm form)
|
||||
{
|
||||
var userId = this.User.FindFirstValue("sub");
|
||||
var userId = this.User.GetUserId();
|
||||
var jti = User.FindFirstValue("jti");
|
||||
try
|
||||
{
|
||||
|
||||
@@ -10,5 +10,8 @@ namespace System.Security.Claims
|
||||
private readonly static string[] SUBSCRIBED_CLAIMS = ["believer", "education", "essential", "pro", "legacy_pro"];
|
||||
public static bool IsUserSubscribed(this ClaimsPrincipal user)
|
||||
=> user.Claims.Any((c) => c.Type == "notesnook:status" && SUBSCRIBED_CLAIMS.Contains(c.Value));
|
||||
|
||||
public static string GetUserId(this ClaimsPrincipal user)
|
||||
=> user.FindFirstValue("sub") ?? throw new Exception("User ID not found in claims.");
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace Notesnook.API.Jobs
|
||||
{
|
||||
public class DeviceCleanupJob : IJob
|
||||
{
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
public Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
ParallelOptions parallelOptions = new()
|
||||
{
|
||||
@@ -59,6 +59,7 @@ namespace Notesnook.API.Jobs
|
||||
}
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ namespace Notesnook.API.Models
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
[BsonElement("type")]
|
||||
public string Type { get; set; }
|
||||
public required string Type { get; set; }
|
||||
|
||||
[JsonPropertyName("timestamp")]
|
||||
[BsonElement("timestamp")]
|
||||
@@ -48,7 +48,7 @@ namespace Notesnook.API.Models
|
||||
|
||||
[JsonPropertyName("platforms")]
|
||||
[BsonElement("platforms")]
|
||||
public string[] Platforms { get; set; }
|
||||
public required string[] Platforms { get; set; }
|
||||
|
||||
[JsonPropertyName("isActive")]
|
||||
[BsonElement("isActive")]
|
||||
@@ -56,7 +56,7 @@ namespace Notesnook.API.Models
|
||||
|
||||
[JsonPropertyName("userTypes")]
|
||||
[BsonElement("userTypes")]
|
||||
public string[] UserTypes { get; set; }
|
||||
public required string[] UserTypes { get; set; }
|
||||
|
||||
[JsonPropertyName("appVersion")]
|
||||
[BsonElement("appVersion")]
|
||||
@@ -64,63 +64,63 @@ namespace Notesnook.API.Models
|
||||
|
||||
[JsonPropertyName("body")]
|
||||
[BsonElement("body")]
|
||||
public BodyComponent[] Body { get; set; }
|
||||
public required BodyComponent[] Body { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[BsonElement("userIds")]
|
||||
public string[] UserIds { get; set; }
|
||||
public string[]? UserIds { get; set; }
|
||||
|
||||
|
||||
[Obsolete]
|
||||
[JsonPropertyName("title")]
|
||||
[DataMember(Name = "title")]
|
||||
[BsonElement("title")]
|
||||
public string Title { get; set; }
|
||||
public string? Title { get; set; }
|
||||
|
||||
[Obsolete]
|
||||
[JsonPropertyName("description")]
|
||||
[BsonElement("description")]
|
||||
public string Description { get; set; }
|
||||
public string? Description { get; set; }
|
||||
|
||||
[Obsolete]
|
||||
[JsonPropertyName("callToActions")]
|
||||
[BsonElement("callToActions")]
|
||||
public CallToAction[] CallToActions { get; set; }
|
||||
public CallToAction[]? CallToActions { get; set; }
|
||||
}
|
||||
|
||||
public class BodyComponent
|
||||
{
|
||||
[JsonPropertyName("type")]
|
||||
[BsonElement("type")]
|
||||
public string Type { get; set; }
|
||||
public required string Type { get; set; }
|
||||
|
||||
[JsonPropertyName("platforms")]
|
||||
[BsonElement("platforms")]
|
||||
public string[] Platforms { get; set; }
|
||||
public string[]? Platforms { get; set; }
|
||||
|
||||
[JsonPropertyName("style")]
|
||||
[BsonElement("style")]
|
||||
public Style Style { get; set; }
|
||||
public Style? Style { get; set; }
|
||||
|
||||
[JsonPropertyName("src")]
|
||||
[BsonElement("src")]
|
||||
public string Src { get; set; }
|
||||
public string? Src { get; set; }
|
||||
|
||||
[JsonPropertyName("text")]
|
||||
[BsonElement("text")]
|
||||
public string Text { get; set; }
|
||||
public string? Text { get; set; }
|
||||
|
||||
[JsonPropertyName("value")]
|
||||
[BsonElement("value")]
|
||||
public string Value { get; set; }
|
||||
public string? Value { get; set; }
|
||||
|
||||
[JsonPropertyName("items")]
|
||||
[BsonElement("items")]
|
||||
public BodyComponent[] Items { get; set; }
|
||||
public BodyComponent[]? Items { get; set; }
|
||||
|
||||
[JsonPropertyName("actions")]
|
||||
[BsonElement("actions")]
|
||||
public CallToAction[] Actions { get; set; }
|
||||
public required CallToAction[] Actions { get; set; }
|
||||
}
|
||||
|
||||
public class Style
|
||||
@@ -135,25 +135,25 @@ namespace Notesnook.API.Models
|
||||
|
||||
[JsonPropertyName("textAlign")]
|
||||
[BsonElement("textAlign")]
|
||||
public string TextAlign { get; set; }
|
||||
public string? TextAlign { get; set; }
|
||||
}
|
||||
|
||||
public class CallToAction
|
||||
{
|
||||
[JsonPropertyName("type")]
|
||||
[BsonElement("type")]
|
||||
public string Type { get; set; }
|
||||
public required string Type { get; set; }
|
||||
|
||||
[JsonPropertyName("platforms")]
|
||||
[BsonElement("platforms")]
|
||||
public string[] Platforms { get; set; }
|
||||
public string[]? Platforms { get; set; }
|
||||
|
||||
[JsonPropertyName("data")]
|
||||
[BsonElement("data")]
|
||||
public string Data { get; set; }
|
||||
public string? Data { get; set; }
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
[BsonElement("title")]
|
||||
public string Title { get; set; }
|
||||
public string? Title { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,9 @@ namespace Notesnook.API.Models;
|
||||
|
||||
public class CompleteMultipartUploadRequestWrapper
|
||||
{
|
||||
public string Key { get; set; }
|
||||
public List<PartETagWrapper> PartETags { get; set; }
|
||||
public string UploadId { get; set; }
|
||||
public required string Key { get; set; }
|
||||
public required List<PartETagWrapper> PartETags { get; set; }
|
||||
public required string UploadId { get; set; }
|
||||
|
||||
public CompleteMultipartUploadRequest ToRequest()
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Notesnook.API.Models
|
||||
public class DeleteAccountForm
|
||||
{
|
||||
[Required]
|
||||
public string Password
|
||||
public required string Password
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
@@ -26,25 +26,19 @@ using System.Text.Json.Serialization;
|
||||
namespace Notesnook.API.Models
|
||||
{
|
||||
[MessagePack.MessagePackObject]
|
||||
public class EncryptedData : IEncrypted
|
||||
public class EncryptedData
|
||||
{
|
||||
[MessagePack.Key("iv")]
|
||||
[JsonPropertyName("iv")]
|
||||
[BsonElement("iv")]
|
||||
[DataMember(Name = "iv")]
|
||||
public string IV
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public required string IV { get; set; }
|
||||
|
||||
[MessagePack.Key("cipher")]
|
||||
[JsonPropertyName("cipher")]
|
||||
[BsonElement("cipher")]
|
||||
[DataMember(Name = "cipher")]
|
||||
public string Cipher
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public required string Cipher { get; set; }
|
||||
|
||||
[MessagePack.Key("length")]
|
||||
[JsonPropertyName("length")]
|
||||
@@ -56,9 +50,9 @@ namespace Notesnook.API.Models
|
||||
[JsonPropertyName("salt")]
|
||||
[BsonElement("salt")]
|
||||
[DataMember(Name = "salt")]
|
||||
public string Salt { get; set; }
|
||||
public required string Salt { get; set; }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is EncryptedData encryptedData)
|
||||
{
|
||||
|
||||
@@ -37,16 +37,16 @@ namespace Notesnook.API.Models
|
||||
[BsonRepresentation(BsonType.ObjectId)]
|
||||
[JsonIgnore]
|
||||
[MessagePack.IgnoreMember]
|
||||
public string Id { get; set; }
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("userId")]
|
||||
public string UserId { get; set; }
|
||||
public required string UserId { get; set; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
public required string Name { get; set; }
|
||||
|
||||
[JsonPropertyName("key")]
|
||||
public string Key { get; set; }
|
||||
public string Key { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("dateCreated")]
|
||||
public long DateCreated { get; set; }
|
||||
|
||||
@@ -31,19 +31,13 @@ namespace Notesnook.API.Models
|
||||
[JsonPropertyName("key")]
|
||||
[MessagePack.Key("key")]
|
||||
[Required]
|
||||
public EncryptedKey Key
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public required EncryptedKey Key { get; set; }
|
||||
|
||||
[DataMember(Name = "salt")]
|
||||
[JsonPropertyName("salt")]
|
||||
[MessagePack.Key("salt")]
|
||||
[Required]
|
||||
public string Salt
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public required string Salt { get; set; }
|
||||
}
|
||||
|
||||
[MessagePack.MessagePackObject]
|
||||
@@ -53,19 +47,13 @@ namespace Notesnook.API.Models
|
||||
[JsonPropertyName("alg")]
|
||||
[MessagePack.Key("alg")]
|
||||
[Required]
|
||||
public string Algorithm
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public required string Algorithm { get; set; }
|
||||
|
||||
[DataMember(Name = "cipher")]
|
||||
[JsonPropertyName("cipher")]
|
||||
[MessagePack.Key("cipher")]
|
||||
[Required]
|
||||
public string Cipher
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public required string Cipher { get; set; }
|
||||
|
||||
[JsonPropertyName("length")]
|
||||
[DataMember(Name = "length")]
|
||||
|
||||
@@ -29,15 +29,9 @@ namespace Notesnook.API.Models
|
||||
[BsonId]
|
||||
[BsonIgnoreIfDefault]
|
||||
[BsonRepresentation(BsonType.ObjectId)]
|
||||
public string Id
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public required string Id { get; set; }
|
||||
|
||||
public string ItemId
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public required string ItemId { get; set; }
|
||||
}
|
||||
|
||||
public class Monograph
|
||||
@@ -50,23 +44,17 @@ namespace Notesnook.API.Models
|
||||
[DataMember(Name = "id")]
|
||||
[JsonPropertyName("id")]
|
||||
[MessagePack.Key("id")]
|
||||
public string ItemId
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string? ItemId { get; set; }
|
||||
|
||||
[BsonId]
|
||||
[BsonIgnoreIfDefault]
|
||||
[BsonRepresentation(BsonType.ObjectId)]
|
||||
[JsonIgnore]
|
||||
[MessagePack.IgnoreMember]
|
||||
public string Id
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public string Title { get; set; }
|
||||
public string? Title { get; set; }
|
||||
|
||||
[JsonPropertyName("userId")]
|
||||
public string? UserId { get; set; }
|
||||
|
||||
@@ -28,8 +28,8 @@ namespace Notesnook.API.Models
|
||||
public class MonographContent
|
||||
{
|
||||
[JsonPropertyName("data")]
|
||||
public string Data { get; set; }
|
||||
public required string Data { get; set; }
|
||||
[JsonPropertyName("type")]
|
||||
public string Type { get; set; }
|
||||
public required string Type { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ namespace Notesnook.API.Models
|
||||
}
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public required string Title { get; set; }
|
||||
public string? Title { get; set; }
|
||||
|
||||
[JsonPropertyName("selfDestruct")]
|
||||
public bool SelfDestruct { get; set; }
|
||||
|
||||
@@ -17,11 +17,13 @@ You should have received a copy of the Affero GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Notesnook.API.Models
|
||||
{
|
||||
public class MultipartUploadMeta
|
||||
{
|
||||
public string UploadId { get; set; }
|
||||
public string[] Parts { get; set; }
|
||||
public string UploadId { get; set; } = string.Empty;
|
||||
public string[] Parts { get; set; } = Array.Empty<string>();
|
||||
}
|
||||
}
|
||||
@@ -3,5 +3,5 @@
|
||||
public class PartETagWrapper
|
||||
{
|
||||
public int PartNumber { get; set; }
|
||||
public string ETag { get; set; }
|
||||
public string ETag { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -6,9 +6,9 @@ namespace Notesnook.API.Models.Responses
|
||||
public class SignupResponse : Response
|
||||
{
|
||||
[JsonPropertyName("userId")]
|
||||
public string UserId { get; set; }
|
||||
public string? UserId { get; set; }
|
||||
|
||||
[JsonPropertyName("errors")]
|
||||
public string[] Errors { get; set; }
|
||||
public string[]? Errors { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace Notesnook.API.Models
|
||||
{
|
||||
public class S3Options
|
||||
{
|
||||
public string ServiceUrl { get; set; }
|
||||
public string Region { get; set; }
|
||||
public string AccessKeyId { get; set; }
|
||||
public string SecretAccessKey { get; set; }
|
||||
public string ServiceUrl { get; set; } = string.Empty;
|
||||
public string Region { get; set; } = string.Empty;
|
||||
public string AccessKeyId { get; set; } = string.Empty;
|
||||
public string SecretAccessKey { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -53,20 +53,14 @@ namespace Notesnook.API.Models
|
||||
[DataMember(Name = "iv")]
|
||||
[MessagePack.Key("iv")]
|
||||
[Required]
|
||||
public string IV
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string IV { get; set; } = string.Empty;
|
||||
|
||||
|
||||
[JsonPropertyName("cipher")]
|
||||
[DataMember(Name = "cipher")]
|
||||
[MessagePack.Key("cipher")]
|
||||
[Required]
|
||||
public string Cipher
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string Cipher { get; set; } = string.Empty;
|
||||
|
||||
[DataMember(Name = "id")]
|
||||
[JsonPropertyName("id")]
|
||||
@@ -108,10 +102,7 @@ namespace Notesnook.API.Models
|
||||
[DataMember(Name = "alg")]
|
||||
[MessagePack.Key("alg")]
|
||||
[Required]
|
||||
public string Algorithm
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string Algorithm { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class SyncItemBsonSerializer : SerializerBase<SyncItem>
|
||||
|
||||
@@ -29,23 +29,23 @@ namespace Notesnook.API.Models
|
||||
public long UpdatedAt { get; set; }
|
||||
}
|
||||
|
||||
public class UserSettings : IUserSettings
|
||||
public class UserSettings
|
||||
{
|
||||
public UserSettings()
|
||||
{
|
||||
this.Id = ObjectId.GenerateNewId().ToString();
|
||||
this.Id = ObjectId.GenerateNewId();
|
||||
}
|
||||
public string UserId { get; set; }
|
||||
public required string UserId { get; set; }
|
||||
public long LastSynced { get; set; }
|
||||
public string Salt { get; set; }
|
||||
public required string Salt { get; set; }
|
||||
public EncryptedData? VaultKey { get; set; }
|
||||
public EncryptedData? AttachmentsKey { get; set; }
|
||||
public EncryptedData? MonographPasswordsKey { get; set; }
|
||||
public InboxKeys? InboxKeys { get; set; }
|
||||
public Limit StorageLimit { get; set; }
|
||||
public Limit? StorageLimit { get; set; }
|
||||
|
||||
[BsonId]
|
||||
[BsonRepresentation(BsonType.ObjectId)]
|
||||
public string Id { get; set; }
|
||||
public ObjectId Id { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Notesnook.API
|
||||
{
|
||||
options.Limits.MaxRequestBodySize = long.MaxValue;
|
||||
options.ListenAnyIP(Servers.NotesnookAPI.Port);
|
||||
if (Servers.NotesnookAPI.IsSecure)
|
||||
if (Servers.NotesnookAPI.IsSecure && Servers.NotesnookAPI.SSLCertificate != null)
|
||||
{
|
||||
options.ListenAnyIP(443, listenerOptions =>
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace Notesnook.API.Services
|
||||
public async Task CreateUserAsync()
|
||||
{
|
||||
SignupResponse response = await httpClient.ForwardAsync<SignupResponse>(this.HttpContextAccessor, $"{Servers.IdentityServer}/signup", HttpMethod.Post);
|
||||
if (!response.Success || (response.Errors != null && response.Errors.Length > 0))
|
||||
if (!response.Success || (response.Errors != null && response.Errors.Length > 0) || response.UserId == null)
|
||||
{
|
||||
logger.LogError("Failed to sign up user: {Response}", JsonSerializer.Serialize(response));
|
||||
if (response.Errors != null && response.Errors.Length > 0)
|
||||
@@ -216,7 +216,7 @@ namespace Notesnook.API.Services
|
||||
await S3Service.DeleteDirectoryAsync(userId);
|
||||
}
|
||||
|
||||
public async Task DeleteUserAsync(string userId, string jti, string password)
|
||||
public async Task DeleteUserAsync(string userId, string? jti, string password)
|
||||
{
|
||||
logger.LogInformation("Deleting user account: {UserId}", userId);
|
||||
|
||||
@@ -227,7 +227,7 @@ namespace Notesnook.API.Services
|
||||
|
||||
await WampServers.MessengerServer.PublishMessageAsync(MessengerServerTopics.SendSSETopic, new SendSSEMessage
|
||||
{
|
||||
SendToAll = false,
|
||||
SendToAll = jti == null,
|
||||
OriginTokenId = jti,
|
||||
UserId = userId,
|
||||
Message = new Message
|
||||
|
||||
@@ -119,8 +119,8 @@ namespace Notesnook.API
|
||||
policy.RequireAuthenticatedUser();
|
||||
});
|
||||
|
||||
options.DefaultPolicy = options.GetPolicy("Notesnook");
|
||||
}).AddSingleton<IAuthorizationMiddlewareResultHandler, AuthorizationResultTransformer>(); ;
|
||||
options.DefaultPolicy = options.GetPolicy("Notesnook") ?? throw new Exception("Notesnook policy not found");
|
||||
}).AddSingleton<IAuthorizationMiddlewareResultHandler, AuthorizationResultTransformer>();
|
||||
|
||||
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddOAuth2Introspection("introspection", options =>
|
||||
@@ -138,13 +138,13 @@ namespace Notesnook.API
|
||||
|
||||
options.Events.OnTokenValidated = (context) =>
|
||||
{
|
||||
if (long.TryParse(context.Principal.FindFirst("exp")?.Value, out long expiryTime))
|
||||
if (long.TryParse(context.Principal?.FindFirst("exp")?.Value, out long expiryTime))
|
||||
{
|
||||
context.Properties.ExpiresUtc = DateTimeOffset.FromUnixTimeSeconds(expiryTime);
|
||||
}
|
||||
context.Properties.AllowRefresh = true;
|
||||
context.Properties.IsPersistent = true;
|
||||
context.HttpContext.User = context.Principal;
|
||||
context.HttpContext.User = context.Principal ?? throw new Exception("No principal found in token.");
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
options.CacheKeyGenerator = (options, token) => (token + ":" + "reference_token").Sha256();
|
||||
@@ -289,11 +289,6 @@ namespace Notesnook.API
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
endpoints.MapHealthChecks("/health");
|
||||
endpoints.MapHub<SyncHub>("/hubs/sync", options =>
|
||||
{
|
||||
options.CloseOnAuthenticationExpiration = false;
|
||||
options.Transports = HttpTransportType.WebSockets;
|
||||
});
|
||||
endpoints.MapHub<SyncV2Hub>("/hubs/sync/v2", options =>
|
||||
{
|
||||
options.CloseOnAuthenticationExpiration = false;
|
||||
@@ -307,7 +302,7 @@ namespace Notesnook.API
|
||||
{
|
||||
public static IServiceCollection AddMongoCollection(this IServiceCollection services, string collectionName, string database = "notesnook")
|
||||
{
|
||||
services.AddKeyedSingleton(collectionName, (provider, key) => MongoDbContext.GetMongoCollection<SyncItem>(provider.GetService<MongoDB.Driver.IMongoClient>(), database, collectionName));
|
||||
services.AddKeyedSingleton(collectionName, (provider, key) => MongoDbContext.GetMongoCollection<SyncItem>(provider.GetRequiredService<MongoDB.Driver.IMongoClient>(), database, collectionName));
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user