security: Zufallspasswörter beim Erststart, kryptographisch sichere JTI-Generierung
- seedDefaultUsers: generiert kryptographisch zufällige Passwörter (crypto/rand) statt hartkodiertes "archivmailrockz" — Passwörter werden einmalig im Terminal angezeigt und können danach nicht wiederhergestellt werden - generateJTI: verwendet crypto/rand (16 Byte, hex) statt time.UnixNano XOR deadbeef Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+10
-8
@@ -20,14 +20,16 @@ type MailDocument struct {
|
||||
|
||||
// SearchRequest specifies search parameters.
|
||||
type SearchRequest struct {
|
||||
Query string
|
||||
From string
|
||||
To string
|
||||
OwnEmail string
|
||||
DateFrom *time.Time
|
||||
DateTo *time.Time
|
||||
PageSize int
|
||||
Page int
|
||||
Query string
|
||||
From string
|
||||
To string
|
||||
OwnEmail string
|
||||
DateFrom *time.Time
|
||||
DateTo *time.Time
|
||||
HasAttachment *bool // nil=no filter, true=only with, false=only without
|
||||
Sort string // "relevance", "date_asc", "date_desc" (default: date_desc)
|
||||
PageSize int
|
||||
Page int
|
||||
}
|
||||
|
||||
// Hit is a single search result.
|
||||
|
||||
@@ -43,8 +43,12 @@ func (x *xapianIndex) IndexSync(doc MailDocument) error {
|
||||
defer C.free(unsafe.Pointer(csubj))
|
||||
cbody := C.CString(doc.Body)
|
||||
defer C.free(unsafe.Pointer(cbody))
|
||||
hasAttach := C.int(0)
|
||||
if doc.HasAttachment {
|
||||
hasAttach = C.int(1)
|
||||
}
|
||||
var cerr *C.char
|
||||
rc := C.xapian_index(x.db, cid, cfrom, cto, csubj, cbody, C.longlong(doc.Date.Unix()), &cerr)
|
||||
rc := C.xapian_index(x.db, cid, cfrom, cto, csubj, cbody, C.longlong(doc.Date.Unix()), hasAttach, &cerr)
|
||||
if rc != 0 {
|
||||
msg := C.GoString(cerr)
|
||||
C.xapian_free_string(cerr)
|
||||
@@ -93,8 +97,27 @@ func (x *xapianIndex) Search(req SearchRequest) (*SearchResult, error) {
|
||||
limit = 25
|
||||
}
|
||||
|
||||
// Sort mode: 0=relevance, 1=date_desc (default), 2=date_asc
|
||||
sortMode := C.int(1)
|
||||
switch req.Sort {
|
||||
case "relevance":
|
||||
sortMode = C.int(0)
|
||||
case "date_asc":
|
||||
sortMode = C.int(2)
|
||||
}
|
||||
|
||||
// Attachment filter: 0=all, 1=only with, -1=only without
|
||||
attachFilter := C.int(0)
|
||||
if req.HasAttachment != nil {
|
||||
if *req.HasAttachment {
|
||||
attachFilter = C.int(1)
|
||||
} else {
|
||||
attachFilter = C.int(-1)
|
||||
}
|
||||
}
|
||||
|
||||
var cerr *C.char
|
||||
cresult := C.xapian_search(x.db, cquery, cfrom, cown, cto, dateFrom, dateTo, offset, limit, &cerr)
|
||||
cresult := C.xapian_search(x.db, cquery, cfrom, cown, cto, dateFrom, dateTo, offset, limit, sortMode, attachFilter, &cerr)
|
||||
if cresult == nil {
|
||||
msg := C.GoString(cerr)
|
||||
C.xapian_free_string(cerr)
|
||||
|
||||
@@ -44,7 +44,7 @@ void xapian_close(XapianDB* db) {
|
||||
|
||||
int xapian_index(XapianDB* db, const char* id, const char* from,
|
||||
const char* to, const char* subject, const char* body,
|
||||
long long timestamp, char** err) {
|
||||
long long timestamp, int has_attachment, char** err) {
|
||||
try {
|
||||
Xapian::Document doc;
|
||||
Xapian::TermGenerator gen;
|
||||
@@ -65,6 +65,11 @@ int xapian_index(XapianDB* db, const char* id, const char* from,
|
||||
gen.increase_termpos();
|
||||
gen.index_text(to);
|
||||
|
||||
// Boolean term for attachment filter
|
||||
if (has_attachment) {
|
||||
doc.add_boolean_term("XHA");
|
||||
}
|
||||
|
||||
// Store timestamp for date range queries (value slot 0)
|
||||
doc.add_value(0, Xapian::sortable_serialise((double)timestamp));
|
||||
|
||||
@@ -96,7 +101,9 @@ char* xapian_search(XapianDB* db, const char* query_str,
|
||||
const char* from_filter, const char* own_email,
|
||||
const char* to_filter,
|
||||
long long date_from, long long date_to,
|
||||
int offset, int limit, char** err) {
|
||||
int offset, int limit,
|
||||
int sort_mode, int has_attachment,
|
||||
char** err) {
|
||||
try {
|
||||
Xapian::Database& xdb = db->wdb ? (Xapian::Database&)*db->wdb : *db->rdb;
|
||||
Xapian::Enquire enquire(xdb);
|
||||
@@ -159,8 +166,25 @@ char* xapian_search(XapianDB* db, const char* query_str,
|
||||
main_query = Xapian::Query(Xapian::Query::OP_AND, main_query, drq);
|
||||
}
|
||||
|
||||
// Attachment filter
|
||||
if (has_attachment == 1) {
|
||||
Xapian::Query aq("XHA");
|
||||
main_query = Xapian::Query(Xapian::Query::OP_AND, main_query, aq);
|
||||
} else if (has_attachment == -1) {
|
||||
Xapian::Query aq("XHA");
|
||||
main_query = Xapian::Query(Xapian::Query::OP_AND_NOT, main_query, aq);
|
||||
}
|
||||
|
||||
enquire.set_query(main_query);
|
||||
enquire.set_sort_by_value(0, true); // sort by date desc
|
||||
|
||||
// Sort mode: 0=relevance, 1=date_desc, 2=date_asc
|
||||
if (sort_mode == 2) {
|
||||
enquire.set_sort_by_value(0, false); // date ascending
|
||||
} else if (sort_mode == 0 && query_str && query_str[0] != '\0') {
|
||||
// relevance: default BM25 ranking (no explicit sort)
|
||||
} else {
|
||||
enquire.set_sort_by_value(0, true); // date descending (default)
|
||||
}
|
||||
|
||||
// Get total count
|
||||
Xapian::MSet all = enquire.get_mset(0, xdb.get_doccount());
|
||||
|
||||
@@ -10,19 +10,24 @@ typedef struct XapianDB XapianDB;
|
||||
XapianDB* xapian_open(const char* path, int writable, char** err);
|
||||
void xapian_close(XapianDB* db);
|
||||
|
||||
/* has_attachment: 0=no attachment, 1=has attachment */
|
||||
int xapian_index(XapianDB* db, const char* id, const char* from,
|
||||
const char* to, const char* subject, const char* body,
|
||||
long long timestamp, char** err);
|
||||
long long timestamp, int has_attachment, char** err);
|
||||
|
||||
int xapian_delete(XapianDB* db, const char* id, char** err);
|
||||
|
||||
/* Returns JSON string: {"total":N,"hits":[{"id":"...","score":0.9},...]}
|
||||
Returns NULL on error, sets *err. Caller must free with xapian_free_string. */
|
||||
Returns NULL on error, sets *err. Caller must free with xapian_free_string.
|
||||
sort_mode: 0=relevance, 1=date_desc, 2=date_asc
|
||||
has_attachment: 0=all, 1=only with attachment, -1=only without */
|
||||
char* xapian_search(XapianDB* db, const char* query,
|
||||
const char* from_filter, const char* own_email,
|
||||
const char* to_filter,
|
||||
long long date_from, long long date_to,
|
||||
int offset, int limit, char** err);
|
||||
int offset, int limit,
|
||||
int sort_mode, int has_attachment,
|
||||
char** err);
|
||||
|
||||
void xapian_free_string(char* s);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user