Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ WaveBox

A free, open source personal media server written in C# and available on all platforms thanks to the Mono framework.

Licensed under [The GNU General Public License v3.0](https://www.gnu.org/licenses/gpl.html "Permalink to The GNU General Public License v3.0 - GNU Project"), for more information please read the [LICENSE.md](https://github.com/einsteinx2/WaveBox/blob/main/LICENSE.md) file in this repository or visit the preceding link to the GNU website.
Licensed under [The GNU General Public License v3.0](https://www.gnu.org/licenses/gpl.html "Permalink to The GNU General Public License v3.0 - GNU Project"), for more information please read the [LICENSE.md](LICENSE.md) file in this repository or visit the preceding link to the GNU website.

API
---

WaveBox features a very extensible JSON API, and is built with API developers in mind! Full API documentation can be found in [API_DOCS.md](https://github.com/einsteinx2/WaveBox/blob/main/API_DOCS.md).
WaveBox features a very extensible JSON API, and is built with API developers in mind! Full API documentation can be found in [API_DOCS.md](API_DOCS.md).

Testing
-------
Expand Down
1 change: 1 addition & 0 deletions WaveBox.Core/WaveBox.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.*" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.*" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.*" />
</ItemGroup>
Expand Down
6 changes: 6 additions & 0 deletions WaveBox.Core/src/BaseClasses.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@

int Execute(string query, params object[] args);

/// <summary>
/// Executes every statement in a SQL script, for schema and migration files. Execute()
/// only ever runs the first statement it is given.
/// </summary>
void ExecuteScript(string script);

T ExecuteScalar<T>(string query, params object[] args);

List<T> Query<T>(string query, params object[] args) where T : new();
Expand Down Expand Up @@ -191,7 +197,7 @@
case InsertType.Replace:
return "REPLACE";
default:
throw new ArgumentOutOfRangeException("InsertType");

Check warning on line 200 in WaveBox.Core/src/BaseClasses.cs

View workflow job for this annotation

GitHub Actions / tests (ubuntu-latest)

Method QueryText passes 'InsertType' as the paramName argument to a ArgumentOutOfRangeException constructor. Replace this argument with one of the method's parameter names. Note that the provided parameter name should have the exact casing as declared on the method. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2208)
}
}
}
Expand Down
22 changes: 3 additions & 19 deletions WaveBox.Core/src/Extensions/ByteExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,11 @@
namespace WaveBox.Core.Extensions {
public static class ByteExtensions {
/// <summary>
/// Generates a MD5 sum of a given byte array
/// Thanks: http://msdn.microsoft.com/en-us/library/s02tk69a.aspx
/// Generates a MD5 sum of a given byte array, as lowercase hex
/// <summary>
public static string MD5(this byte[] input) {
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create()) {
// Convert the input string to a byte array and compute the hash.
byte[] data = md5.ComputeHash(input);

// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder();

// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++) {
sBuilder.Append(data[i].ToString("x2"));
}

// Return the hexadecimal string.
return sBuilder.ToString();
}
byte[] hash = System.Security.Cryptography.MD5.HashData(input);
return Convert.ToHexString(hash).ToLowerInvariant();
}
}
}
12 changes: 6 additions & 6 deletions WaveBox.Core/src/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ public static bool IsTrue(this string boolString) {
}

/// <summary>
/// Generates a MD5 sum of a given string
/// Generates a MD5 sum of a given string, as lowercase hex
/// <summary>
public static string MD5(this string sumthis) {
if (sumthis == "" || sumthis == null) {
return "";
}

MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
return BitConverter.ToString(md5.ComputeHash(System.Text.Encoding.ASCII.GetBytes(sumthis)), 0);
byte[] hash = System.Security.Cryptography.MD5.HashData(Encoding.ASCII.GetBytes(sumthis));
return Convert.ToHexString(hash).ToLowerInvariant();
}

/// <summary>
Expand Down Expand Up @@ -84,15 +84,15 @@ public static int MonthForAbbreviation(this string abb) {
}

/// <summary>
/// Generates a SHA1 sum of a given string
/// Generates a SHA1 sum of a given string, as lowercase hex
/// </summary>
public static string SHA1(this string sumthis) {
if (sumthis == "" || sumthis == null) {
return "";
}

SHA1CryptoServiceProvider provider = new SHA1CryptoServiceProvider();
return BitConverter.ToString(provider.ComputeHash(Encoding.ASCII.GetBytes(sumthis))).Replace("-", "");
byte[] hash = System.Security.Cryptography.SHA1.HashData(Encoding.ASCII.GetBytes(sumthis));
return Convert.ToHexString(hash).ToLowerInvariant();
}

/// <summary>
Expand Down
6 changes: 4 additions & 2 deletions WaveBox.Core/src/Injection/Interfaces/IDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ public interface IDatabase {

int Version { get; }

string DatabaseTemplatePath { get; }
string DatabaseSchemaPath { get; }
string DatabasePath { get; }

string QuerylogTemplatePath { get; }
string MigrationsPath { get; }

string QuerylogSchemaPath { get; }
string QuerylogPath { get; }

void DatabaseSetup();
Expand Down
2 changes: 1 addition & 1 deletion WaveBox.Core/src/Model/Playlist.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public string CalculateHash() {
Injection.Get<IDatabase>().CloseSqliteConnection(conn);
}

return itemIds.ToString().MD5().Replace("-", string.Empty);
return itemIds.ToString().MD5();
}

public void UpdateDatabase() {
Expand Down
61 changes: 7 additions & 54 deletions WaveBox.Core/src/Model/User.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using Cirrious.MvvmCross.Plugins.Sqlite;
using System.Text.Json.Serialization;
using WaveBox.Core.Extensions;
Expand All @@ -12,9 +10,6 @@

namespace WaveBox.Core.Model {
public class User : IGroupingItem {
// PBKDF2 iterations
public const int HashIterations = 2500;

private static readonly WaveBox.Core.Logging.ILog logger = WaveBox.Core.Logging.LogManager.GetLogger();

[JsonPropertyName("userId")]
Expand All @@ -39,9 +34,6 @@ public class User : IGroupingItem {
[JsonIgnore]
public string PasswordHash { get; set; }

[JsonIgnore]
public string PasswordSalt { get; set; }

[JsonIgnore, IgnoreRead, IgnoreWrite]
public string SessionId { get; set; }

Expand Down Expand Up @@ -106,17 +98,18 @@ public IList<Session> ListOfSessions() {
}

public bool UpdatePassword(string password) {
string salt = GeneratePasswordSalt();
string hash = ComputePasswordHash(password, salt);
string hash = PasswordHasher.Hash(password);
if (hash == null) {
return false;
}

ISQLiteConnection conn = null;
try {
conn = Injection.Get<IDatabase>().GetSqliteConnection();
int affected = conn.Execute("UPDATE User SET PasswordHash = ?, PasswordSalt = ? WHERE UserId = ?", hash, salt, this.UserId);
int affected = conn.Execute("UPDATE User SET PasswordHash = ? WHERE UserId = ?", hash, this.UserId);

if (affected > 0) {
this.PasswordHash = hash;
this.PasswordSalt = salt;

return Injection.Get<IUserRepository>().UpdateUserCache(this);
}
Expand Down Expand Up @@ -212,24 +205,9 @@ public bool UpdateRole(Role role) {
return false;
}

// Verify password, using timing attack resistant approach
// Credit to PHP5.5 Password API for this method
// Verify password; the comparison is timing attack resistant
public bool Authenticate(string password) {
// Compute hash
string hash = ComputePasswordHash(password, this.PasswordSalt);

// Ensure hashes are same length
if (hash.Length != this.PasswordHash.Length) {
return false;
}

// Compare ASCII value of each character, bitwise OR any diff
int status = 0;
for (int i = 0; i < hash.Length; i++) {
status |= ((int)hash[i] ^ (int)this.PasswordHash[i]);
}

return status == 0;
return PasswordHasher.Verify(password, this.PasswordHash);
}

public bool CreateSession(string password, string clientName) {
Expand Down Expand Up @@ -281,30 +259,5 @@ public static int CompareUsersByName(User x, User y) {
return StringComparer.OrdinalIgnoreCase.Compare(x.UserName, y.UserName);
}

// Compute password hash using PBKDF2
public static string ComputePasswordHash(string password, string salt, int iterations = HashIterations) {
// Convert salt to byte array
byte[] saltBytes = Encoding.UTF8.GetBytes(salt);

// Hash using PBKDF2 with salt and predefined iterations
using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, saltBytes, iterations)) {
var key = pbkdf2.GetBytes(64);
return Convert.ToBase64String(key);
}
}

// Use RNG crypto service to generate random bytes for salt
public static string GeneratePasswordSalt() {
// Create byte array to store salt
byte[] salt = new byte[32];

// Fill array using RNG
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) {
rng.GetBytes(salt);
}

// Return string representation
return Convert.ToBase64String(salt);
}
}
}
7 changes: 4 additions & 3 deletions WaveBox.Core/src/Repository/UserRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,17 @@ public User CreateUser(string userName, string password, Role role, long? delete
return new User();
}

string salt = User.GeneratePasswordSalt();
string hash = User.ComputePasswordHash(password, salt);
string hash = PasswordHasher.Hash(password);
if (hash == null) {
return null;
}

var u = new User();
u.UserId = itemId;
u.UserName = userName;
u.Role = role;
u.Password = password;
u.PasswordHash = hash;
u.PasswordSalt = salt;
u.CreateTime = DateTime.UtcNow.ToUnixTime();
u.DeleteTime = deleteTime;

Expand Down
98 changes: 91 additions & 7 deletions WaveBox.Core/src/SQLiteNet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,15 @@
/// <returns>
/// The number of rows modified in the database as a result of this execution.
/// </returns>
/// <summary>
/// WaveBox addition: executes every statement in a SQL script. Execute() above only ever
/// runs the first, since sqlite3_prepare_v2 compiles one statement at a time.
/// Takes no parameters -- this is for schema and migration scripts, not queries.
/// </summary>
public void ExecuteScript(string script) {
SQLite3.ExecuteScript(Handle, script);
}

public int Execute(string query, params object[] args) {
var cmd = CreateCommand(query, args);

Expand Down Expand Up @@ -990,13 +999,7 @@
if (Int32.TryParse(savepoint.Substring(firstLen + 1), out depth)) {
// TODO: Mild race here, but inescapable without locking almost everywhere.
if (0 <= depth && depth < _trasactionDepth) {
#if NETFX_CORE
Volatile.Write (ref _trasactionDepth, depth);
#elif SILVERLIGHT
_trasactionDepth = depth;
#else
Thread.VolatileWrite(ref _trasactionDepth, depth);
#endif
Volatile.Write(ref _trasactionDepth, depth);
Execute(cmd + savepoint);
return;
}
Expand Down Expand Up @@ -2366,29 +2369,29 @@

#if !WINDOWS_PHONE
[DllImport("e_sqlite3", EntryPoint = "sqlite3_open", CallingConvention = CallingConvention.Cdecl)]
public static extern Result Open([MarshalAs(UnmanagedType.LPStr)] string filename, out IntPtr db);

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (ubuntu-latest)

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (ubuntu-latest)

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (macos-latest)

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (macos-latest)

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (windows-latest)

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (windows-latest)

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-x64

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-x64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-arm64

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-arm64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-x64

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-x64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-arm64

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-arm64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-arm64

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-arm64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-x64

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2372 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-x64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

[DllImport("e_sqlite3", EntryPoint = "sqlite3_open_v2", CallingConvention = CallingConvention.Cdecl)]
public static extern Result Open([MarshalAs(UnmanagedType.LPStr)] string filename, out IntPtr db, int flags,

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (ubuntu-latest)

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (ubuntu-latest)

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (macos-latest)

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (macos-latest)

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (windows-latest)

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (windows-latest)

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-x64

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-x64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-arm64

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-arm64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-x64

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-x64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-arm64

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-arm64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-arm64

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-arm64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-x64

Specify marshaling for P/Invoke string arguments (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2101)

Check warning on line 2375 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-x64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)
IntPtr zvfs);

[DllImport("e_sqlite3", EntryPoint = "sqlite3_open_v2", CallingConvention = CallingConvention.Cdecl)]
public static extern Result Open(byte[] filename, out IntPtr db, int flags, IntPtr zvfs);

Check warning on line 2379 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (ubuntu-latest)

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2379 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (macos-latest)

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2379 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (windows-latest)

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2379 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-x64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2379 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-arm64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2379 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-x64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2379 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-arm64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2379 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-arm64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2379 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-x64

P/Invoke method 'Open' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

[DllImport("e_sqlite3", EntryPoint = "sqlite3_open16", CallingConvention = CallingConvention.Cdecl)]
public static extern Result Open16([MarshalAs(UnmanagedType.LPWStr)] string filename, out IntPtr db);

Check warning on line 2382 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (ubuntu-latest)

P/Invoke method 'Open16' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2382 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (macos-latest)

P/Invoke method 'Open16' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2382 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (windows-latest)

P/Invoke method 'Open16' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2382 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-x64

P/Invoke method 'Open16' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2382 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-arm64

P/Invoke method 'Open16' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2382 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-x64

P/Invoke method 'Open16' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2382 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-arm64

P/Invoke method 'Open16' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2382 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-arm64

P/Invoke method 'Open16' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2382 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-x64

P/Invoke method 'Open16' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

[DllImport("e_sqlite3", EntryPoint = "sqlite3_close", CallingConvention = CallingConvention.Cdecl)]
public static extern Result Close(IntPtr db);

Check warning on line 2385 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (macos-latest)

P/Invoke method 'Close' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2385 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (windows-latest)

P/Invoke method 'Close' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2385 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-x64

P/Invoke method 'Close' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2385 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-arm64

P/Invoke method 'Close' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2385 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-x64

P/Invoke method 'Close' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2385 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-arm64

P/Invoke method 'Close' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2385 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-arm64

P/Invoke method 'Close' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2385 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-x64

P/Invoke method 'Close' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

[DllImport("e_sqlite3", EntryPoint = "sqlite3_config", CallingConvention = CallingConvention.Cdecl)]
public static extern Result Config(ConfigOption option);

Check warning on line 2388 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (ubuntu-latest)

P/Invoke method 'Config' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2388 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (macos-latest)

P/Invoke method 'Config' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2388 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (windows-latest)

P/Invoke method 'Config' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2388 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-x64

P/Invoke method 'Config' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2388 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-arm64

P/Invoke method 'Config' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2388 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-x64

P/Invoke method 'Config' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2388 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-arm64

P/Invoke method 'Config' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2388 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-arm64

P/Invoke method 'Config' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2388 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-x64

P/Invoke method 'Config' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

[DllImport("e_sqlite3", EntryPoint = "sqlite3_busy_timeout", CallingConvention = CallingConvention.Cdecl)]
public static extern Result BusyTimeout(IntPtr db, int milliseconds);

Check warning on line 2391 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (ubuntu-latest)

P/Invoke method 'BusyTimeout' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2391 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (macos-latest)

P/Invoke method 'BusyTimeout' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2391 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (windows-latest)

P/Invoke method 'BusyTimeout' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2391 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-x64

P/Invoke method 'BusyTimeout' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2391 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-arm64

P/Invoke method 'BusyTimeout' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2391 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-x64

P/Invoke method 'BusyTimeout' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2391 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-arm64

P/Invoke method 'BusyTimeout' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2391 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-arm64

P/Invoke method 'BusyTimeout' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2391 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-x64

P/Invoke method 'BusyTimeout' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

[DllImport("e_sqlite3", EntryPoint = "sqlite3_changes", CallingConvention = CallingConvention.Cdecl)]
public static extern int Changes(IntPtr db);

Check warning on line 2394 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (ubuntu-latest)

P/Invoke method 'Changes' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2394 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (macos-latest)

P/Invoke method 'Changes' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2394 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / tests (windows-latest)

P/Invoke method 'Changes' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2394 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-x64

P/Invoke method 'Changes' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2394 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / osx-arm64

P/Invoke method 'Changes' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2394 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-x64

P/Invoke method 'Changes' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2394 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / linux-arm64

P/Invoke method 'Changes' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2394 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-arm64

P/Invoke method 'Changes' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

Check warning on line 2394 in WaveBox.Core/src/SQLiteNet.cs

View workflow job for this annotation

GitHub Actions / win-x64

P/Invoke method 'Changes' should not be visible (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1401)

[DllImport("e_sqlite3", EntryPoint = "sqlite3_prepare_v2", CallingConvention = CallingConvention.Cdecl)]
public static extern Result Prepare2(IntPtr db, [MarshalAs(UnmanagedType.LPStr)] string sql, int numBytes,
Expand All @@ -2403,6 +2406,87 @@
return stmt;
}

// WaveBox addition: the overload above discards pzTail, so it only ever compiles the
// first statement of a script. This one hands back the pointer to the remaining SQL,
// which is what lets ExecuteScript walk a multi-statement file.
[DllImport("e_sqlite3", EntryPoint = "sqlite3_prepare_v2", CallingConvention = CallingConvention.Cdecl)]
public static extern Result Prepare2(IntPtr db, IntPtr sql, int numBytes,
out IntPtr stmt, out IntPtr pzTail);

/// <summary>
/// WaveBox addition: runs every statement in a SQL script.
///
/// SQLite's parser does the tokenizing, so semicolons inside string literals, comments
/// and trigger bodies are all handled correctly -- unlike splitting the text on ';'.
/// The script is marshalled as an explicit UTF-8 buffer and walked by byte offset,
/// avoiding the ANSI marshalling and char-vs-byte length bugs in the string overload
/// of Prepare2 above.
///
/// Transactions are the caller's business; scripts should not contain BEGIN or COMMIT.
/// </summary>
public static void ExecuteScript(IntPtr db, string script) {
if (String.IsNullOrEmpty(script)) {
return;
}

byte[] utf8 = System.Text.Encoding.UTF8.GetBytes(script);
// sqlite3_prepare_v2 wants a NUL-terminated buffer when it reads past numBytes
Array.Resize(ref utf8, utf8.Length + 1);

GCHandle pin = GCHandle.Alloc(utf8, GCHandleType.Pinned);
try {
IntPtr start = pin.AddrOfPinnedObject();
int offset = 0;

// utf8.Length - 1 excludes the NUL we appended
while (offset < utf8.Length - 1) {
IntPtr stmt;
IntPtr tail;
Result r = Prepare2(db, start + offset, utf8.Length - 1 - offset, out stmt, out tail);

if (r != Result.OK) {
throw SQLiteException.New(r, GetErrmsg(db) + "\n" + RemainingText(utf8, offset));
}

int nextOffset = (int)(tail.ToInt64() - start.ToInt64());

// A trailing run of whitespace or comments compiles to no statement at all
if (stmt == IntPtr.Zero) {
if (nextOffset <= offset) {
break;
}
offset = nextOffset;
continue;
}

try {
Result step = Step(stmt);
if (step != Result.Done && step != Result.Row) {
throw SQLiteException.New(step, GetErrmsg(db) + "\n" + StatementText(utf8, offset, nextOffset));
}
} finally {
Finalize(stmt);
}

if (nextOffset <= offset) {
break;
}
offset = nextOffset;
}
} finally {
pin.Free();
}
}

private static string StatementText(byte[] utf8, int offset, int end) {
return System.Text.Encoding.UTF8.GetString(utf8, offset, Math.Max(0, end - offset)).Trim();
}

private static string RemainingText(byte[] utf8, int offset) {
// On a compile failure there is no tail to bound the statement, so show what is left
return System.Text.Encoding.UTF8.GetString(utf8, offset, utf8.Length - 1 - offset).Trim();
}

[DllImport("e_sqlite3", EntryPoint = "sqlite3_step", CallingConvention = CallingConvention.Cdecl)]
public static extern Result Step(IntPtr stmt);

Expand Down
Loading
Loading