warp-server 0.2.3__tar.gz → 0.2.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {warp_server-0.2.3 → warp_server-0.2.8}/PKG-INFO +51 -1
- {warp_server-0.2.3 → warp_server-0.2.8}/README.md +50 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/pyproject.toml +1 -1
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/cli.py +68 -1
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/config.py +1 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/main.py +33 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/models.py +21 -0
- warp_server-0.2.8/src/warp_server/routers/bndbs.py +215 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/files.py +12 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/schemas.py +22 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/static/index.html +123 -1
- {warp_server-0.2.3 → warp_server-0.2.8}/uv.lock +53 -53
- {warp_server-0.2.3 → warp_server-0.2.8}/.github/workflows/ci.yml +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/.gitignore +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/.gitmodules +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/.pre-commit-config.yaml +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/Dockerfile +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/__init__.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/auth.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/database.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/BasicBlock.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/BasicBlockGUID.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/Constraint.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/ConstraintGUID.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/Function.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/FunctionComment.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/FunctionGUID.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/FunctionVariable.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/SignatureChunk.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/__init__.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SymbolBin/Symbol.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SymbolBin/SymbolClass.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SymbolBin/SymbolModifiers.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SymbolBin/__init__.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TargetBin/Target.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TargetBin/__init__.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Array.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/ArrayModifiers.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/BitOffset.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/BitShift.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/BitSize.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/BitWidth.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Boolean.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/CallingConvention.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Character.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/ComputedType.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Enumeration.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/EnumerationMember.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Float.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Function.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/FunctionMember.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Integer.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/LocationClass.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/MetadataValueType.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Pointer.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/PointerAddressing.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Referrer.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/RegisterLocation.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/StackLocation.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Structure.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/StructureMember.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/StructureMemberModifiers.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Type.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/TypeChunk.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/TypeClass.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/TypeGUID.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/TypeMetadata.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/TypeModifiers.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Union.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/UnionMember.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/UnsignedBitOffset.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Void.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/__init__.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/Warp/Chunk.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/Warp/ChunkHeader.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/Warp/ChunkType.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/Warp/CompressionType.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/Warp/File.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/Warp/FileHeader.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/Warp/__init__.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/__init__.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/__init__.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/auth.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/commits.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/functions.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/search.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/sources.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/status.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/symbols.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/targets.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/types.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/users.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/warp_parser.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/tests/__init__.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/tests/conftest.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_commits.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_files.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_functions.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_ingest.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_lockout.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_search.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_sources.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_status.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_targets.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_users.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_warp_parser.py +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/.git +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/.github/workflows/CI.yaml +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/.gitignore +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/Cargo.toml +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/LICENSE +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/README.md +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/about.hbs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/about.toml +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/Cargo.toml +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/benches/chunk.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/benches/type.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/build.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/examples/dumper.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/examples/random.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/examples/type_builder.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/fixtures/random.warp +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/fuzz/.gitignore +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/fuzz/Cargo.toml +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/fuzz/fuzz_targets/file.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/fuzz/fuzz_targets/function.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/fuzz/fuzz_targets/type.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/cached_builder.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/chunk.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/mod.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/basic_block_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/basic_block_guid_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/constraint_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/constraint_guid_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/function_comment_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/function_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/function_guid_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/function_variable_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/signature_chunk_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/symbol_bin/symbol_class_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/symbol_bin/symbol_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/symbol_bin/symbol_modifiers_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/target_bin/target_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/array_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/array_modifiers_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/bit_offset_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/bit_shift_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/bit_size_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/bit_width_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/boolean_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/calling_convention_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/character_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/computed_type_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/enumeration_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/enumeration_member_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/float_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/function_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/function_member_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/function_member_location_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/integer_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/location_class_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/metadata_value_type_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/pointer_addressing_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/pointer_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/referrer_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/register_location_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/stack_location_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/structure_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/structure_member_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/structure_member_modifiers_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/type_chunk_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/type_class_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/type_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/type_guid_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/type_metadata_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/type_modifiers_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/union_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/union_member_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/unsigned_bit_offset_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/void_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/warp/chunk_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/warp/chunk_header_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/warp/chunk_type_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/warp/compression_type_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/warp/file_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/warp/file_header_generated.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/lib.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/mock.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/signature/basic_block.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/signature/chunk.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/signature/comment.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/signature/constraint.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/signature/function.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/signature/variable.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/signature.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/symbol.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/target.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/chunk.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/array.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/boolean.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/character.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/enumeration.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/float.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/function.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/integer.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/pointer.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/referrer.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/structure.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/union.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/void.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/guid.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/tests/chunk.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/tests/file.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/tests/signature.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/tests/snapshots/file__file_format_regression.snap +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/tests/types.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/signature.fbs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/symbol.fbs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/target.fbs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/type.fbs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/warp.fbs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/warp_cli/Cargo.toml +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/warp_cli/src/main.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/warp_cli/src/operation/find.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/warp_cli/src/operation/merge.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/warp_cli/src/operation.rs +0 -0
- {warp_server-0.2.3 → warp_server-0.2.8}/warp/warp_cli/src/utility.rs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: warp-server
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: WARP signature server API
|
|
5
5
|
Requires-Python: >=3.12
|
|
6
6
|
Requires-Dist: aiosqlite>=0.20
|
|
@@ -144,6 +144,54 @@ Log in with your username and API key. The UI lets you:
|
|
|
144
144
|
- Manage users (admin only)
|
|
145
145
|
- Create API keys
|
|
146
146
|
- Browse functions and commits
|
|
147
|
+
- Upload, browse, and download BNDBs
|
|
148
|
+
|
|
149
|
+
## BNDB Sharing
|
|
150
|
+
|
|
151
|
+
The server supports uploading and downloading Binary Ninja Database (`.bndb`) files.
|
|
152
|
+
Files are stored on disk as gzip-compressed blobs in a configurable directory, keeping
|
|
153
|
+
the SQLite metadata database lightweight.
|
|
154
|
+
|
|
155
|
+
Any authenticated user can upload or download BNDBs. Only the uploader (or an admin)
|
|
156
|
+
can delete them.
|
|
157
|
+
|
|
158
|
+
### API
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# upload a BNDB
|
|
162
|
+
curl -X POST http://localhost:8000/api/v1/bndbs \
|
|
163
|
+
-H "Authorization: Bearer <key>" \
|
|
164
|
+
-F "file=@firmware.bndb" \
|
|
165
|
+
-F "name=firmware.bndb" \
|
|
166
|
+
-F "description=Extracted from router firmware"
|
|
167
|
+
|
|
168
|
+
# list / search BNDBs
|
|
169
|
+
curl -X POST http://localhost:8000/api/v1/bndbs/query \
|
|
170
|
+
-H "Authorization: Bearer <key>" \
|
|
171
|
+
-H "Content-Type: application/json" \
|
|
172
|
+
-d '{"name": "firmware", "limit": 20, "page": 1}'
|
|
173
|
+
|
|
174
|
+
# get metadata
|
|
175
|
+
curl -H "Authorization: Bearer <key>" \
|
|
176
|
+
http://localhost:8000/api/v1/bndbs/<uuid>
|
|
177
|
+
|
|
178
|
+
# download
|
|
179
|
+
curl -H "Authorization: Bearer <key>" -o output.bndb \
|
|
180
|
+
http://localhost:8000/api/v1/bndbs/<uuid>/download
|
|
181
|
+
|
|
182
|
+
# delete (owner or admin)
|
|
183
|
+
curl -X DELETE -H "Authorization: Bearer <key>" \
|
|
184
|
+
http://localhost:8000/api/v1/bndbs/<uuid>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
BNDBs can also be managed from the **BNDBs** tab in the web UI.
|
|
188
|
+
|
|
189
|
+
### Storage
|
|
190
|
+
|
|
191
|
+
BNDB files are stored as `<uuid>.bndb.gz` in the directory configured by
|
|
192
|
+
`WARP_BNDB_STORAGE_DIR` (default `./bndb_storage`). The directory is created
|
|
193
|
+
automatically on server startup. Compression is transparent — clients always
|
|
194
|
+
upload and download raw `.bndb` files.
|
|
147
195
|
|
|
148
196
|
## Configuration
|
|
149
197
|
|
|
@@ -157,6 +205,7 @@ The server is configured via environment variables, all prefixed with `WARP_`.
|
|
|
157
205
|
| `WARP_PORT` | `8000` | Listen port. |
|
|
158
206
|
| `WARP_LOG_LEVEL` | `info` | Uvicorn log level (`debug`, `info`, `warning`, `error`). |
|
|
159
207
|
| `WARP_RELOAD` | `false` | Enable auto-reload on file changes (dev only). |
|
|
208
|
+
| `WARP_BNDB_STORAGE_DIR` | `./bndb_storage` | Directory for uploaded BNDB files (created automatically). |
|
|
160
209
|
| `WARP_CORS_ORIGINS` | `[]` | JSON list of allowed CORS origins, e.g. `'["https://app.example.com"]'`. |
|
|
161
210
|
| `WARP_TRUSTED_PROXIES` | `[]` | JSON list of trusted reverse-proxy IPs allowed to set `X-Forwarded-For`. |
|
|
162
211
|
| `WARP_MAX_LOGIN_ATTEMPTS` | `5` | Failed attempts before an IP or user account is locked. |
|
|
@@ -202,3 +251,4 @@ Migrations are idempotent and safe to re-run. Current migrations:
|
|
|
202
251
|
|
|
203
252
|
- **hash-keys** — hashes any plaintext API keys (SHA-256). After migration, previously issued raw keys become invalid; create new ones via `warp-ctl key create` or the web UI.
|
|
204
253
|
- **lockout-columns** — adds `locked`, `failed_login_count`, and `locked_at` columns to the `users` table for account lockout support.
|
|
254
|
+
- **purge-auto-names** — deletes functions and symbols with auto-generated names (`sub_`, `nullsub`, `j_sub_`, `outlined_sub_`, `_OUTLINED_FUNCTION`).
|
|
@@ -128,6 +128,54 @@ Log in with your username and API key. The UI lets you:
|
|
|
128
128
|
- Manage users (admin only)
|
|
129
129
|
- Create API keys
|
|
130
130
|
- Browse functions and commits
|
|
131
|
+
- Upload, browse, and download BNDBs
|
|
132
|
+
|
|
133
|
+
## BNDB Sharing
|
|
134
|
+
|
|
135
|
+
The server supports uploading and downloading Binary Ninja Database (`.bndb`) files.
|
|
136
|
+
Files are stored on disk as gzip-compressed blobs in a configurable directory, keeping
|
|
137
|
+
the SQLite metadata database lightweight.
|
|
138
|
+
|
|
139
|
+
Any authenticated user can upload or download BNDBs. Only the uploader (or an admin)
|
|
140
|
+
can delete them.
|
|
141
|
+
|
|
142
|
+
### API
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# upload a BNDB
|
|
146
|
+
curl -X POST http://localhost:8000/api/v1/bndbs \
|
|
147
|
+
-H "Authorization: Bearer <key>" \
|
|
148
|
+
-F "file=@firmware.bndb" \
|
|
149
|
+
-F "name=firmware.bndb" \
|
|
150
|
+
-F "description=Extracted from router firmware"
|
|
151
|
+
|
|
152
|
+
# list / search BNDBs
|
|
153
|
+
curl -X POST http://localhost:8000/api/v1/bndbs/query \
|
|
154
|
+
-H "Authorization: Bearer <key>" \
|
|
155
|
+
-H "Content-Type: application/json" \
|
|
156
|
+
-d '{"name": "firmware", "limit": 20, "page": 1}'
|
|
157
|
+
|
|
158
|
+
# get metadata
|
|
159
|
+
curl -H "Authorization: Bearer <key>" \
|
|
160
|
+
http://localhost:8000/api/v1/bndbs/<uuid>
|
|
161
|
+
|
|
162
|
+
# download
|
|
163
|
+
curl -H "Authorization: Bearer <key>" -o output.bndb \
|
|
164
|
+
http://localhost:8000/api/v1/bndbs/<uuid>/download
|
|
165
|
+
|
|
166
|
+
# delete (owner or admin)
|
|
167
|
+
curl -X DELETE -H "Authorization: Bearer <key>" \
|
|
168
|
+
http://localhost:8000/api/v1/bndbs/<uuid>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
BNDBs can also be managed from the **BNDBs** tab in the web UI.
|
|
172
|
+
|
|
173
|
+
### Storage
|
|
174
|
+
|
|
175
|
+
BNDB files are stored as `<uuid>.bndb.gz` in the directory configured by
|
|
176
|
+
`WARP_BNDB_STORAGE_DIR` (default `./bndb_storage`). The directory is created
|
|
177
|
+
automatically on server startup. Compression is transparent — clients always
|
|
178
|
+
upload and download raw `.bndb` files.
|
|
131
179
|
|
|
132
180
|
## Configuration
|
|
133
181
|
|
|
@@ -141,6 +189,7 @@ The server is configured via environment variables, all prefixed with `WARP_`.
|
|
|
141
189
|
| `WARP_PORT` | `8000` | Listen port. |
|
|
142
190
|
| `WARP_LOG_LEVEL` | `info` | Uvicorn log level (`debug`, `info`, `warning`, `error`). |
|
|
143
191
|
| `WARP_RELOAD` | `false` | Enable auto-reload on file changes (dev only). |
|
|
192
|
+
| `WARP_BNDB_STORAGE_DIR` | `./bndb_storage` | Directory for uploaded BNDB files (created automatically). |
|
|
144
193
|
| `WARP_CORS_ORIGINS` | `[]` | JSON list of allowed CORS origins, e.g. `'["https://app.example.com"]'`. |
|
|
145
194
|
| `WARP_TRUSTED_PROXIES` | `[]` | JSON list of trusted reverse-proxy IPs allowed to set `X-Forwarded-For`. |
|
|
146
195
|
| `WARP_MAX_LOGIN_ATTEMPTS` | `5` | Failed attempts before an IP or user account is locked. |
|
|
@@ -186,3 +235,4 @@ Migrations are idempotent and safe to re-run. Current migrations:
|
|
|
186
235
|
|
|
187
236
|
- **hash-keys** — hashes any plaintext API keys (SHA-256). After migration, previously issued raw keys become invalid; create new ones via `warp-ctl key create` or the web UI.
|
|
188
237
|
- **lockout-columns** — adds `locked`, `failed_login_count`, and `locked_at` columns to the `users` table for account lockout support.
|
|
238
|
+
- **purge-auto-names** — deletes functions and symbols with auto-generated names (`sub_`, `nullsub`, `j_sub_`, `outlined_sub_`, `_OUTLINED_FUNCTION`).
|
|
@@ -7,7 +7,7 @@ from datetime import datetime, timezone
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
9
|
import click
|
|
10
|
-
from sqlalchemy import inspect, select, text, update
|
|
10
|
+
from sqlalchemy import delete, inspect, select, text, update
|
|
11
11
|
|
|
12
12
|
from warp_server.auth import hash_api_key
|
|
13
13
|
from warp_server.database import async_session, engine
|
|
@@ -15,10 +15,14 @@ from warp_server.models import (
|
|
|
15
15
|
ApiKey,
|
|
16
16
|
Base,
|
|
17
17
|
Commit,
|
|
18
|
+
Function,
|
|
19
|
+
FunctionComment,
|
|
20
|
+
FunctionConstraint,
|
|
18
21
|
LoginAttempt,
|
|
19
22
|
Source,
|
|
20
23
|
SourceTag,
|
|
21
24
|
SourceUser,
|
|
25
|
+
Symbol,
|
|
22
26
|
User,
|
|
23
27
|
)
|
|
24
28
|
|
|
@@ -604,6 +608,66 @@ async def _migration_lockout_columns(conn, db, apply: bool) -> bool:
|
|
|
604
608
|
return True
|
|
605
609
|
|
|
606
610
|
|
|
611
|
+
_IGNORED_NAME_PREFIXES = (
|
|
612
|
+
"sub_",
|
|
613
|
+
"nullsub",
|
|
614
|
+
"j_sub_",
|
|
615
|
+
"outlined_sub_",
|
|
616
|
+
"_OUTLINED_FUNCTION",
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
async def _migration_purge_auto_names(db, apply: bool) -> bool:
|
|
621
|
+
"""Delete functions/symbols with auto-generated names (sub_, nullsub, etc.)."""
|
|
622
|
+
sym_sub = (
|
|
623
|
+
select(Symbol.id)
|
|
624
|
+
.where(
|
|
625
|
+
Symbol.name.like("sub_%")
|
|
626
|
+
| Symbol.name.like("nullsub%")
|
|
627
|
+
| Symbol.name.like("j_sub_%")
|
|
628
|
+
| Symbol.name.like("outlined_sub_%")
|
|
629
|
+
| Symbol.name.like("_OUTLINED_FUNCTION%")
|
|
630
|
+
)
|
|
631
|
+
.scalar_subquery()
|
|
632
|
+
)
|
|
633
|
+
|
|
634
|
+
func_sub = (
|
|
635
|
+
select(Function.id).where(Function.symbol_id.in_(sym_sub)).scalar_subquery()
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
result = await db.execute(
|
|
639
|
+
select(
|
|
640
|
+
select(Symbol.id).where(Symbol.id.in_(sym_sub)).count(),
|
|
641
|
+
select(Function.id).where(Function.id.in_(func_sub)).count(),
|
|
642
|
+
)
|
|
643
|
+
)
|
|
644
|
+
n_symbols, n_functions = result.one()
|
|
645
|
+
|
|
646
|
+
if n_symbols == 0:
|
|
647
|
+
return False
|
|
648
|
+
|
|
649
|
+
click.echo(
|
|
650
|
+
f" purge-auto-names: {n_symbols} symbol(s), {n_functions} function(s) to purge"
|
|
651
|
+
)
|
|
652
|
+
if apply:
|
|
653
|
+
await db.execute(
|
|
654
|
+
delete(FunctionComment).where(FunctionComment.function_id.in_(func_sub))
|
|
655
|
+
)
|
|
656
|
+
await db.execute(
|
|
657
|
+
delete(FunctionConstraint).where(
|
|
658
|
+
FunctionConstraint.function_id.in_(func_sub)
|
|
659
|
+
)
|
|
660
|
+
)
|
|
661
|
+
await db.execute(delete(Function).where(Function.symbol_id.in_(sym_sub)))
|
|
662
|
+
await db.execute(delete(Symbol).where(Symbol.id.in_(sym_sub)))
|
|
663
|
+
await db.commit()
|
|
664
|
+
click.echo(
|
|
665
|
+
f" purge-auto-names: purged {n_functions} function(s) "
|
|
666
|
+
f"and {n_symbols} symbol(s)"
|
|
667
|
+
)
|
|
668
|
+
return True
|
|
669
|
+
|
|
670
|
+
|
|
607
671
|
@app.command("migrate")
|
|
608
672
|
@click.option(
|
|
609
673
|
"--apply", is_flag=True, help="Actually write changes (default is dry-run)."
|
|
@@ -629,6 +693,9 @@ def migrate(apply):
|
|
|
629
693
|
if await _migration_lockout_columns(conn, db, apply):
|
|
630
694
|
pending += 1
|
|
631
695
|
|
|
696
|
+
if await _migration_purge_auto_names(db, apply):
|
|
697
|
+
pending += 1
|
|
698
|
+
|
|
632
699
|
if pending == 0:
|
|
633
700
|
click.echo("Everything up to date — no migrations needed.")
|
|
634
701
|
elif not apply:
|
|
@@ -11,6 +11,7 @@ class Settings(BaseSettings):
|
|
|
11
11
|
lockout_duration_minutes: int = 30
|
|
12
12
|
reload: bool = False
|
|
13
13
|
debug: bool = False
|
|
14
|
+
bndb_storage_dir: str = "./bndb_storage"
|
|
14
15
|
# IPs of trusted reverse proxies allowed to set X-Forwarded-For
|
|
15
16
|
trusted_proxies: list[str] = []
|
|
16
17
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import gzip
|
|
1
2
|
import logging
|
|
2
3
|
import time
|
|
3
4
|
from contextlib import asynccontextmanager
|
|
@@ -14,6 +15,7 @@ from warp_server.database import engine
|
|
|
14
15
|
from warp_server.models import Base
|
|
15
16
|
from warp_server.routers import (
|
|
16
17
|
auth,
|
|
18
|
+
bndbs,
|
|
17
19
|
commits,
|
|
18
20
|
files,
|
|
19
21
|
functions,
|
|
@@ -33,6 +35,7 @@ logger = logging.getLogger("warp_server")
|
|
|
33
35
|
async def lifespan(app: FastAPI):
|
|
34
36
|
async with engine.begin() as conn:
|
|
35
37
|
await conn.run_sync(Base.metadata.create_all)
|
|
38
|
+
Path(settings.bndb_storage_dir).mkdir(parents=True, exist_ok=True)
|
|
36
39
|
yield
|
|
37
40
|
await engine.dispose()
|
|
38
41
|
|
|
@@ -47,6 +50,35 @@ app = FastAPI(
|
|
|
47
50
|
)
|
|
48
51
|
|
|
49
52
|
|
|
53
|
+
@app.middleware("http")
|
|
54
|
+
async def decompress_gzip_request(request: Request, call_next):
|
|
55
|
+
if request.headers.get("content-encoding") == "gzip":
|
|
56
|
+
body = await request.body()
|
|
57
|
+
try:
|
|
58
|
+
decompressed = gzip.decompress(body)
|
|
59
|
+
except Exception:
|
|
60
|
+
pass
|
|
61
|
+
else:
|
|
62
|
+
scope = request.scope
|
|
63
|
+
|
|
64
|
+
# Replace body with decompressed data
|
|
65
|
+
async def receive():
|
|
66
|
+
return {
|
|
67
|
+
"type": "http.request",
|
|
68
|
+
"body": decompressed,
|
|
69
|
+
"more_body": False,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
request = Request(scope, receive)
|
|
73
|
+
# Remove content-encoding so downstream doesn't re-process
|
|
74
|
+
if "content-encoding" in request.headers.keys():
|
|
75
|
+
raw_headers = [
|
|
76
|
+
(k, v) for k, v in scope["headers"] if k != b"content-encoding"
|
|
77
|
+
]
|
|
78
|
+
scope["headers"] = raw_headers
|
|
79
|
+
return await call_next(request)
|
|
80
|
+
|
|
81
|
+
|
|
50
82
|
@app.middleware("http")
|
|
51
83
|
async def log_request_duration(request: Request, call_next):
|
|
52
84
|
start = time.perf_counter()
|
|
@@ -73,6 +105,7 @@ app.include_router(functions.router)
|
|
|
73
105
|
app.include_router(files.router)
|
|
74
106
|
app.include_router(types.router)
|
|
75
107
|
app.include_router(search.router)
|
|
108
|
+
app.include_router(bndbs.router)
|
|
76
109
|
|
|
77
110
|
# -- Static web UI ---------------------------------------------------------
|
|
78
111
|
_static_dir = Path(__file__).parent / "static"
|
|
@@ -252,3 +252,24 @@ class Type(Base):
|
|
|
252
252
|
created_at = Column(
|
|
253
253
|
DateTime, default=lambda: datetime.now(timezone.utc), nullable=False
|
|
254
254
|
)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
# ── BNDBs ────────────────────────────────────────────────────────────
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class Bndb(Base):
|
|
261
|
+
__tablename__ = "bndbs"
|
|
262
|
+
|
|
263
|
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
264
|
+
uuid = Column(Uuid, unique=True, nullable=False, default=uuid.uuid4)
|
|
265
|
+
name = Column(String, nullable=False)
|
|
266
|
+
description = Column(Text, nullable=True)
|
|
267
|
+
user_id = Column(
|
|
268
|
+
Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True
|
|
269
|
+
)
|
|
270
|
+
size_original = Column(Integer, nullable=False)
|
|
271
|
+
size_compressed = Column(Integer, nullable=False)
|
|
272
|
+
sha256 = Column(String(64), nullable=False)
|
|
273
|
+
created_at = Column(
|
|
274
|
+
DateTime, default=lambda: datetime.now(timezone.utc), nullable=False
|
|
275
|
+
)
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import gzip
|
|
3
|
+
import hashlib
|
|
4
|
+
import logging
|
|
5
|
+
import math
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from uuid import UUID, uuid4
|
|
8
|
+
|
|
9
|
+
from fastapi import APIRouter, Depends, Form, HTTPException, UploadFile, status
|
|
10
|
+
from fastapi.responses import StreamingResponse
|
|
11
|
+
from sqlalchemy import func, select
|
|
12
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
13
|
+
|
|
14
|
+
from warp_server.auth import get_current_user
|
|
15
|
+
from warp_server.config import settings
|
|
16
|
+
from warp_server.database import get_db
|
|
17
|
+
from warp_server.models import Bndb, User
|
|
18
|
+
from warp_server.schemas import BndbMdl, BndbQueryRequest, PaginatedResponse
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
router = APIRouter(prefix="/api/v1/bndbs", tags=["bndbs"])
|
|
23
|
+
|
|
24
|
+
CHUNK_SIZE = 256 * 1024 # 256 KB
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _storage_dir() -> Path:
|
|
28
|
+
return Path(settings.bndb_storage_dir)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _bndb_path(bndb_uuid: UUID) -> Path:
|
|
32
|
+
return _storage_dir() / f"{bndb_uuid}.bndb.gz"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _bndb_to_response(bndb: Bndb, username: str | None = None) -> BndbMdl:
|
|
36
|
+
return BndbMdl(
|
|
37
|
+
id=bndb.id,
|
|
38
|
+
uuid=bndb.uuid,
|
|
39
|
+
name=bndb.name,
|
|
40
|
+
description=bndb.description,
|
|
41
|
+
user_id=bndb.user_id,
|
|
42
|
+
username=username,
|
|
43
|
+
size_original=bndb.size_original,
|
|
44
|
+
size_compressed=bndb.size_compressed,
|
|
45
|
+
sha256=bndb.sha256,
|
|
46
|
+
created_at=bndb.created_at,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
async def _stream_compress_upload(
|
|
51
|
+
upload: UploadFile, dest: Path
|
|
52
|
+
) -> tuple[int, int, str]:
|
|
53
|
+
"""Stream an upload through gzip to disk.
|
|
54
|
+
|
|
55
|
+
Returns (original_size, compressed_size, sha256_hex).
|
|
56
|
+
"""
|
|
57
|
+
sha = hashlib.sha256()
|
|
58
|
+
original_size = 0
|
|
59
|
+
|
|
60
|
+
def _write_sync():
|
|
61
|
+
nonlocal original_size
|
|
62
|
+
with gzip.open(dest, "wb", compresslevel=6) as gz:
|
|
63
|
+
while True:
|
|
64
|
+
chunk = upload.file.read(CHUNK_SIZE)
|
|
65
|
+
if not chunk:
|
|
66
|
+
break
|
|
67
|
+
sha.update(chunk)
|
|
68
|
+
original_size += len(chunk)
|
|
69
|
+
gz.write(chunk)
|
|
70
|
+
|
|
71
|
+
await asyncio.to_thread(_write_sync)
|
|
72
|
+
|
|
73
|
+
compressed_size = dest.stat().st_size
|
|
74
|
+
return original_size, compressed_size, sha.hexdigest()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@router.post("", response_model=BndbMdl)
|
|
78
|
+
async def upload_bndb(
|
|
79
|
+
file: UploadFile,
|
|
80
|
+
name: str = Form(...),
|
|
81
|
+
description: str | None = Form(None),
|
|
82
|
+
db: AsyncSession = Depends(get_db),
|
|
83
|
+
user: User = Depends(get_current_user),
|
|
84
|
+
):
|
|
85
|
+
bndb = Bndb(
|
|
86
|
+
uuid=uuid4(),
|
|
87
|
+
name=name,
|
|
88
|
+
description=description,
|
|
89
|
+
user_id=user.id,
|
|
90
|
+
size_original=0,
|
|
91
|
+
size_compressed=0,
|
|
92
|
+
sha256="",
|
|
93
|
+
)
|
|
94
|
+
dest = _bndb_path(bndb.uuid)
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
original, compressed, sha256_hex = await _stream_compress_upload(file, dest)
|
|
98
|
+
bndb.size_original = original
|
|
99
|
+
bndb.size_compressed = compressed
|
|
100
|
+
bndb.sha256 = sha256_hex
|
|
101
|
+
|
|
102
|
+
db.add(bndb)
|
|
103
|
+
await db.commit()
|
|
104
|
+
await db.refresh(bndb)
|
|
105
|
+
except Exception:
|
|
106
|
+
dest.unlink(missing_ok=True)
|
|
107
|
+
raise
|
|
108
|
+
|
|
109
|
+
logger.info(
|
|
110
|
+
"BNDB upload %s: %d → %d bytes (%.0f%% compression)",
|
|
111
|
+
name,
|
|
112
|
+
original,
|
|
113
|
+
compressed,
|
|
114
|
+
(1 - compressed / original) * 100 if original else 0,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return _bndb_to_response(bndb, user.username)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@router.post("/query", response_model=PaginatedResponse[BndbMdl])
|
|
121
|
+
async def query_bndbs(
|
|
122
|
+
body: BndbQueryRequest,
|
|
123
|
+
db: AsyncSession = Depends(get_db),
|
|
124
|
+
_user: User = Depends(get_current_user),
|
|
125
|
+
):
|
|
126
|
+
limit = body.limit or 50
|
|
127
|
+
page = body.page or 1
|
|
128
|
+
|
|
129
|
+
query = select(Bndb, User.username).outerjoin(User, Bndb.user_id == User.id)
|
|
130
|
+
count_query = select(func.count(Bndb.id))
|
|
131
|
+
|
|
132
|
+
if body.name:
|
|
133
|
+
query = query.where(Bndb.name.ilike(f"%{body.name}%"))
|
|
134
|
+
count_query = count_query.where(Bndb.name.ilike(f"%{body.name}%"))
|
|
135
|
+
|
|
136
|
+
total = (await db.execute(count_query)).scalar() or 0
|
|
137
|
+
total_pages = max(1, math.ceil(total / limit))
|
|
138
|
+
|
|
139
|
+
query = query.order_by(Bndb.created_at.desc())
|
|
140
|
+
query = query.offset((page - 1) * limit).limit(limit)
|
|
141
|
+
|
|
142
|
+
result = await db.execute(query)
|
|
143
|
+
items = [_bndb_to_response(row.Bndb, row.username) for row in result.all()]
|
|
144
|
+
|
|
145
|
+
return PaginatedResponse(items=items, total_pages=total_pages, total_results=total)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@router.get("/{bndb_uuid}", response_model=BndbMdl)
|
|
149
|
+
async def get_bndb(
|
|
150
|
+
bndb_uuid: UUID,
|
|
151
|
+
db: AsyncSession = Depends(get_db),
|
|
152
|
+
_user: User = Depends(get_current_user),
|
|
153
|
+
):
|
|
154
|
+
result = await db.execute(
|
|
155
|
+
select(Bndb, User.username)
|
|
156
|
+
.outerjoin(User, Bndb.user_id == User.id)
|
|
157
|
+
.where(Bndb.uuid == bndb_uuid)
|
|
158
|
+
)
|
|
159
|
+
row = result.one_or_none()
|
|
160
|
+
if row is None:
|
|
161
|
+
raise HTTPException(status_code=404, detail="BNDB not found")
|
|
162
|
+
return _bndb_to_response(row.Bndb, row.username)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@router.get("/{bndb_uuid}/download")
|
|
166
|
+
async def download_bndb(
|
|
167
|
+
bndb_uuid: UUID,
|
|
168
|
+
db: AsyncSession = Depends(get_db),
|
|
169
|
+
_user: User = Depends(get_current_user),
|
|
170
|
+
):
|
|
171
|
+
result = await db.execute(select(Bndb).where(Bndb.uuid == bndb_uuid))
|
|
172
|
+
bndb = result.scalar_one_or_none()
|
|
173
|
+
if bndb is None:
|
|
174
|
+
raise HTTPException(status_code=404, detail="BNDB not found")
|
|
175
|
+
|
|
176
|
+
path = _bndb_path(bndb.uuid)
|
|
177
|
+
if not path.exists():
|
|
178
|
+
raise HTTPException(status_code=404, detail="BNDB file missing from storage")
|
|
179
|
+
|
|
180
|
+
def _decompress_stream():
|
|
181
|
+
with gzip.open(path, "rb") as gz:
|
|
182
|
+
while chunk := gz.read(CHUNK_SIZE):
|
|
183
|
+
yield chunk
|
|
184
|
+
|
|
185
|
+
filename = bndb.name if bndb.name.endswith(".bndb") else bndb.name + ".bndb"
|
|
186
|
+
safe_name = filename.replace('"', "'")
|
|
187
|
+
return StreamingResponse(
|
|
188
|
+
_decompress_stream(),
|
|
189
|
+
media_type="application/octet-stream",
|
|
190
|
+
headers={
|
|
191
|
+
"Content-Disposition": f'attachment; filename="{safe_name}"',
|
|
192
|
+
"Content-Length": str(bndb.size_original),
|
|
193
|
+
},
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@router.delete("/{bndb_uuid}", status_code=status.HTTP_204_NO_CONTENT)
|
|
198
|
+
async def delete_bndb(
|
|
199
|
+
bndb_uuid: UUID,
|
|
200
|
+
db: AsyncSession = Depends(get_db),
|
|
201
|
+
user: User = Depends(get_current_user),
|
|
202
|
+
):
|
|
203
|
+
result = await db.execute(select(Bndb).where(Bndb.uuid == bndb_uuid))
|
|
204
|
+
bndb = result.scalar_one_or_none()
|
|
205
|
+
if bndb is None:
|
|
206
|
+
raise HTTPException(status_code=404, detail="BNDB not found")
|
|
207
|
+
|
|
208
|
+
if bndb.user_id != user.id and user.role != "Admin":
|
|
209
|
+
raise HTTPException(status_code=403, detail="Only the owner or an admin can delete this BNDB")
|
|
210
|
+
|
|
211
|
+
path = _bndb_path(bndb.uuid)
|
|
212
|
+
await db.delete(bndb)
|
|
213
|
+
await db.commit()
|
|
214
|
+
|
|
215
|
+
path.unlink(missing_ok=True)
|
|
@@ -158,6 +158,14 @@ async def push_file_json(
|
|
|
158
158
|
|
|
159
159
|
BATCH_SIZE = 500
|
|
160
160
|
|
|
161
|
+
_IGNORED_NAME_PREFIXES = (
|
|
162
|
+
"sub_",
|
|
163
|
+
"nullsub",
|
|
164
|
+
"j_sub_",
|
|
165
|
+
"outlined_sub_",
|
|
166
|
+
"_OUTLINED_FUNCTION",
|
|
167
|
+
)
|
|
168
|
+
|
|
161
169
|
|
|
162
170
|
async def _get_or_create_target(
|
|
163
171
|
db: AsyncSession,
|
|
@@ -191,6 +199,8 @@ async def _resolve_symbols(
|
|
|
191
199
|
needed: set[tuple[str, str, str]] = set()
|
|
192
200
|
for chunk in chunks:
|
|
193
201
|
for pf in chunk.functions:
|
|
202
|
+
if pf.symbol.name.startswith(_IGNORED_NAME_PREFIXES):
|
|
203
|
+
continue
|
|
194
204
|
needed.add((pf.symbol.name, pf.symbol.symbol_class, pf.symbol.modifier))
|
|
195
205
|
|
|
196
206
|
if not needed:
|
|
@@ -291,6 +301,8 @@ async def _ingest_chunks(
|
|
|
291
301
|
)
|
|
292
302
|
|
|
293
303
|
for pf in chunk.functions:
|
|
304
|
+
if pf.symbol.name.startswith(_IGNORED_NAME_PREFIXES):
|
|
305
|
+
continue
|
|
294
306
|
sym_key = (pf.symbol.name, pf.symbol.symbol_class, pf.symbol.modifier)
|
|
295
307
|
func_rows.append(
|
|
296
308
|
{
|
|
@@ -291,3 +291,25 @@ class SearchResponse(BaseModel):
|
|
|
291
291
|
limit: int
|
|
292
292
|
offset: int
|
|
293
293
|
items: list[SearchIndexRow]
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
# ── BNDBs ────────────────────────────────────────────────────────────
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
class BndbMdl(BaseModel):
|
|
300
|
+
id: int
|
|
301
|
+
uuid: UUID
|
|
302
|
+
name: str
|
|
303
|
+
description: str | None = None
|
|
304
|
+
user_id: int | None = None
|
|
305
|
+
username: str | None = None
|
|
306
|
+
size_original: int
|
|
307
|
+
size_compressed: int
|
|
308
|
+
sha256: str
|
|
309
|
+
created_at: datetime
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
class BndbQueryRequest(BaseModel):
|
|
313
|
+
name: str | None = None
|
|
314
|
+
limit: int | None = Field(None, ge=1, le=200)
|
|
315
|
+
page: int | None = Field(None, ge=1)
|