58 Commits

Author SHA1 Message Date
Cédric Verstraeten
96918255a9 feat: enhance authentication mechanism and improve event handling
- Added EndpointRefAddress to DeviceParams for better endpoint management.
- Updated FilterType to use pointers for TopicExpression and MessageContent.
- Refactored SendSoapWithDigest to strip WS-Security headers to avoid credential duplication.
- Updated package imports to reflect new repository structure.
- Introduced ReadAndParse function for improved HTTP response handling in SDK.
2026-07-07 12:49:51 +00:00
Cédric Verstraeten
2fb619deda Merge branch 'master' into fix/authentication-mechanism 2026-07-07 14:18:26 +02:00
Cédric Verstraeten
119a6511b1 feat(auth): add AuthMode-driven auth with HTTP digest support
On use-go/onvif the only authenticated transport was WS-Security
UsernameToken. Cameras whose firmware requires HTTP digest for
authenticated operations therefore onboarded fine (GetCapabilities is
allowed unauthenticated) but rejected every authenticated call such as
PTZ ContinuousMove, making pan/tilt appear completely broken.

Add an AuthMode selector on DeviceParams and route CallMethod through a
new AuthMode-aware sendSOAP helper:

  - none:          no auth
  - usernametoken: WS-Security only (never escalates to digest)
  - digest:        HTTP digest only
  - both / unset:  WS-Security when credentials exist, plus an HTTP
                   digest retry only when the device answers HTTP 401

networking.SendSoapWithDigest performs a standards-compliant RFC 2617
digest handshake (MD5 / MD5-sess, qop=auth) using only the standard
library, and never strips an existing WS-Security header. The default
(unset AuthMode) stays backward compatible: digest is attempted only on
a genuine 401 challenge, so WS-Security-only cameras are unaffected.

Adds unit tests covering challenge parsing, the RFC 2617 worked example,
authorization-header consistency, and rejection of unsupported qop.
2026-07-07 12:00:16 +00:00
Sebastian Norling
07b0f6c2e0 fix(event/stream): address round-3 review findings
Critical
  - Two-step lock race in renewLoop: getPullPoint() + pullPointGen()
    were separate Lock/Unlock pairs, leaving a window in which a
    concurrent setPullPoint could advance gen between the two reads.
    The renew then ran against ref-N but believed its captured gen
    was N+1, and updateGrantedTerminationIfGen "succeeded" writing
    the old subscription's grant onto the new one — same class of
    bug the generation counter was meant to fix. New snapshotPullPoint
    accessor reads both under one lock.
  - wssePasswordRE was missing the close-tag-or-EOF alternative that
    wsseSecurityRE got last round; a <Password> element truncated at
    the 64 KiB error cap escaped redaction. Pattern is now symmetric.

Important
  - Dropped unused (granted, now) params from nextRenewIntervalAfterError;
    only opts.RetryBackoff is consulted. Tests adjusted.
  - Moved gen field next to pullPointMu with explicit guard comment.
  - Inlined the single-use rootTag helper; nil case handled directly.
  - Loosened TestNextRenewIntervalAfterError_FallsBackToRetryBackoff
    so future jitter doesn't break it.

Docs
  - Extended trust-boundary godoc on SendSoap* to name the full set of
    weaponisable WS-* headers (wsa:To/ReplyTo/FaultTo/MessageID,
    wsu:Timestamp).
  - Mirrored the trust-boundary warning on gosoap.AddStringHeaderContents
    so library consumers see it at the package entry point too.
  - Noted that updateGrantedTerminationIfGen intentionally doesn't bump
    gen (would defeat rotation detection).
  - Documented the wsseSecurityRE truncation-branch trade-off
    (max-redact > max-context for log lines).

Tests
  - TestSnapshotPullPoint_AtomicReadOfRefAndGen pins the new accessor.
  - TestEnrichSOAPErr_RedactsTruncatedPasswordOutsideSecurity exercises
    the now-symmetric password redaction.
  - TestEnrichSOAPErr_RedactsMultipleSecurityBlocks pins existing
    multi-block behaviour.
  - TestBuildRefParamsHeader_RejectsNonReferenceParametersRoot_Table
    covers vendor-suffix, multi-root, and unrelated-element cases.
  - One-line comment on the &Stream{} tests explaining nil-now safety.
2026-05-27 18:07:57 +02:00
Sebastian Norling
d7cfee56a1 fix(event/stream): address round-2 review findings
Critical
  - Renew busy-loop on persistent failure: after a failed
    renewPullPoint, the loop re-read the (now in-past)
    GrantedTermination and nextRenewInterval floored to 1s, hammering
    the camera at 1 Hz until reconnect. nextRenewIntervalAfterError
    decouples the failure path from the stale grant and backs off
    at opts.RetryBackoff. renewLoop also routes through s.now() so
    test clocks can drive it deterministically.
  - Lost-update race on GrantedTermination: a renew result for an
    old subscription could overwrite the grant on a new one if
    attemptRecreate swapped pullPoint mid-flight. A generation
    counter on Stream tracks subscription rotation; the renew loop
    captures the generation before the SOAP call and discards the
    result if the subscription was rotated.
  - Credential leak when <Security> straddled the 64 KiB error cap:
    the non-greedy regex required a closing tag and missed the
    truncated case. wsseSecurityRE now matches close-tag-or-EOF.
    Belt-and-braces wssePasswordRE redacts <Password> elements
    outside any Security wrapper.
  - addHeaderChildren accepted well-formed-but-element-free input
    and produced a header-less request. Now errors out.

Important
  - Wrapper detection in buildRefParamsHeader was HasSuffix-based and
    misfired on children named *ReferenceParameters. Replaced with the
    unambiguous wrapper-only contract: input must be the full
    <*:ReferenceParameters> element returned by extractReferenceParameters.
  - Renamed SoapOption → SendSoapOption and WithHeader → WithSOAPHeader
    to disambiguate at call sites.
  - Renamed WithHeader's `xml` parameter to headerContent to avoid
    shadowing the encoding/xml package name.
  - Documented terminationTimeRE's "first match only" semantics so
    nobody re-uses it from PullMessages context where multiple
    TerminationTime elements appear.
  - goleak is now a direct require (go mod tidy).

Performance
  - Added gosoap.AddStringHeaderContents (plural) for multi-root
    header content. AddStringHeaderContent remains as-is for
    backwards compatibility with external consumers. Device.go's
    addHeaderChildren workaround is gone — one etree parse per
    SendSoapWithOptions call instead of two.

Migration
  - Device.go's own CallOnvifFunction and the three examples now
    call SendSoapWithOptions, modelling the canonical path.

Docs / tests
  - Trust-boundary warning on SendSoapWithHeader/Options godoc.
  - Comments on createPullPointResp/Alt explain why TerminationTime
    is intentionally omitted (renew timing fixtures).
  - New tests: digest retry strips WS-Security, duplicate
    WithSOAPHeader is last-wins, malformed TerminationTime yields
    zero, margin==base falls to base/2, empty SubscriptionReference
    yields empty ref params, Security straddling cap is redacted,
    bare Password redacted, wrapper-only contract is enforced.
2026-05-27 18:07:56 +02:00
Sebastian Norling
c7ef445d6a refactor(onvif): add SendSoapWithOptions as the variadic workhorse
Future per-call knobs (timeout, context, custom namespaces) will arrive
sooner than later. Adding them as SendSoapWithHeader2 / 3 / N would
turn the Device API into a combinatorial mess; adding them as new
required positional args breaks every existing consumer.

SendSoapWithOptions accepts variadic SoapOption values. SendSoap and
SendSoapWithHeader become one-line delegates so all current callers
keep their signatures, and the public surface is purely additive.

Only WithHeader ships today — wiring the AXIS ReferenceParameters
path through the same plumbing. New options land as WithX constructors
in this file rather than as new Device methods.
2026-05-27 18:07:56 +02:00
Sebastian Norling
d726ed8edb fix(event/stream): address review findings on AXIS compat work
Critical
  - Device.SendSoapWithHeader now parses the supplied header content
    with etree and adds each top-level child as its own SOAP Header
    block. gosoap.AddStringHeaderContent only accepts a single root
    element; previously a multi-child ref-params header silently
    produced a header-less request because the parse error was
    discarded. Errors are now propagated.
  - enrichSOAPErr scrubs <*:Security> blocks from response bodies
    before fault extraction or excerpt slicing so a camera that
    echoes the WS-Security header in a fault response cannot leak
    Username/Password into operator logs.

Important
  - extractSOAPFault falls back to the SOAP 1.2 Subcode (e.g.
    ter:InvalidArgs) when Reason/Text is empty — consistent with
    enrichSOAPErr and surfaces actionable detail on 200-OK fault
    bodies reached via unmarshalNode.
  - subscriptionRef captures the camera-granted TerminationTime
    from CreatePullPointSubscription and Renew responses. renewLoop
    schedules from it via the new nextRenewInterval helper so we
    never miss a renew when the camera grants less than requested.
    renew is now a sleep-loop driven by the latest granted time.
  - enrichSOAPErr reads at most 64 KiB from the body (vs. 10 MiB
    on success paths). Fault bodies are always small; the prior cap
    let a wedged camera churn 10 MiB/s through the retry loop.

Suggestions
  - extractReferenceParameters anchors to <SubscriptionReference> so
    a wsa:ReplyTo / wsa:FaultTo that also carries ReferenceParameters
    elsewhere in the envelope cannot leak through and break PullMessages.
  - buildRefParamsHeader accepts either raw children or the full
    <*:ReferenceParameters> wrapper, and propagates ancestor xmlns:*
    onto each child so a vendor that declares the prefix on the
    parent (not the child itself, as AXIS does) still produces valid
    standalone children on the wire.
  - SendSoapWithHeader documents that xmlHeaderContent must be
    well-formed XML and that the caller is responsible for escaping
    any externally sourced data.
  - Error-message ordering is now context-first
    ("SOAP fault: X: <wrapped err>") per Go convention.
  - Dead headerEnd slicing removed from the SendSoapWithHeader test.

Tests
  - End-to-end multi-child wiring through pullMessages.
  - Digest auth retry preserves the injected header.
  - Malformed-XML header content fast-fails before any request.
  - buildRefParamsHeader malformed / whitespace-only edge cases.
  - goleak.VerifyTestMain in event/stream catches any pull/renew
    goroutine that outlives its Stream.

No new behavioural surface added to onvif core; SendSoap retains
its signature, SendSoapWithHeader is the only new public method.
2026-05-27 18:07:56 +02:00
Sebastian Norling
de3f049a63 feat(event/stream): echo WS-Addressing ReferenceParameters for AXIS
AXIS encodes pull-point subscription identity in
<wsa:ReferenceParameters> inside the CreatePullPointSubscription
response — a generic /onvif/services endpoint plus a
<dom0:SubscriptionId> child — rather than a per-subscription URL.
We were discarding the ReferenceParameters and POSTing to the
generic endpoint, which AXIS rejected with ter:InvalidArgs on every
PullMessages/Renew/Unsubscribe.

Per WS-Addressing 1.0 §3.1 each reference parameter MUST be echoed
as a SOAP Header block carrying wsa:IsReferenceParameter="true".

  - subscriptionRef now carries Address + the verbatim
    ReferenceParameters inner XML extracted from the create response.
  - buildRefParamsHeader walks the children, adds the attribute, and
    produces the SOAP Header content.
  - pullMessages, renewPullPoint, unsubscribePullPoint switch from
    SendSoap to a new SendSoapWithHeader path on the caller interface.
  - onvif.Device gains SendSoapWithHeader as a thin variant of
    SendSoap (existing SendSoap is now a one-liner delegating to it
    with empty header content, so all external callers are unaffected).

Verified end-to-end against an AXIS camera at 192.168.1.10: pulls
now stream the full topic tree (VMD, Object Analytics, IO, storage,
hardware-failure topics) instead of looping on ter:InvalidArgs.
2026-05-27 18:07:56 +02:00
Cedric Verstraeten
ede8b81fc8 Update Device.go 2025-01-19 09:58:53 +01:00
Cedric Verstraeten
542f83433b Update Device.go 2025-01-18 09:09:33 +01:00
Cedric Verstraeten
6fc6d9a99e reuse main http client + resolved memory leak (close previous response) before creating new one. 2025-01-16 21:43:28 +01:00
Cedric Verstraeten
ee8a919932 support for latest hikivision ONVIF 19.12 2024-08-21 16:07:06 +02:00
Cedric Verstraeten
8902e4e789 upgrade onvif library 2023-12-18 20:16:21 +01:00
Cedric Verstraeten
71b6d48393 diz memory leak + import 2023-12-06 20:38:25 +01:00
Cedric Verstraeten
bb5a87b253 Merge remote-tracking branch 'upstream/master' 2023-12-06 19:45:28 +01:00
Ivan Šarić
fd737e6327 exports device params, fixes error in comments, adds gitignore file 2023-12-03 11:20:17 +01:00
tarancss
8677b3be7e fix memory leak and events 2022-09-17 01:18:56 +02:00
Jean-Francois Smigielski
6f1154fc4d ws-discovery: Return an error instead of printing & ignoring 2022-05-10 13:21:27 +02:00
Jean-Francois Smigielski
9b5df9ac2c Avoid non-error debug on stdout 2022-05-09 09:13:30 +02:00
刘跃龙
1bfeb9b57d fix:get Extension services 2021-10-25 10:59:11 +08:00
刘跃龙
c5e512ad1a fix:get Extension services 2021-10-25 10:55:46 +08:00
cedricve
37d8a71395 rename imports 2021-06-04 21:51:49 +02:00
kikimor
2fb044d81c endpoint nat support 2021-03-06 23:56:46 +05:00
kikimor
51ae55e8a0 External httpClient support 2021-02-24 21:58:44 +05:00
eamon
6a2c796805 fix case 2021-01-31 16:12:54 +08:00
Edward
928207d461 simple mod to github.com/use-go/onvif 2020-04-29 10:53:49 +08:00
Eamon
56ddaaca0e use a better way in getEndpoint 2018-05-18 09:13:38 +08:00
Eamon
dc42c9d688 fix service url resolving from device map & use an automatic way. 2018-05-17 18:10:19 +08:00
Eamon
f4182a60d9 update string comparison in callmethod 2018-05-16 17:03:28 +08:00
Eamon
9fcfc36610 fix wrong package using 2018-05-16 15:15:25 +08:00
Eamon
57dc05360e Expose Device type for outer developer using & format code file 2018-05-16 14:12:18 +08:00
yakovlevdmv
edeeac2935 WS-Security fixed to correspond YUNCH yc-110ar camera, examples folder added 2018-04-10 22:42:27 +03:00
yakovlevdmv
c9568c7ad5 Merge conflicts 2018-04-10 03:01:17 +03:00
yakovlevdmv
b302c5c92b WS-security update(moved to gosoap progect), return error on HTTP digest authentification required 2018-04-10 02:59:48 +03:00
George Palanjyan
86ca55954a fix bugs 2018-04-10 02:08:46 +03:00
George Palanjyan
cb3bd7e4d8 merge Device.go 2018-04-10 00:18:53 +03:00
George Palanjyan
9c02c509c7 add api 2018-04-10 00:12:58 +03:00
yakovlevdmv
36090abc65 Some improvements 2018-04-08 02:04:58 +03:00
yakovlevdmv
42e62d7f52 Bugs fixed 2018-04-07 22:16:11 +03:00
yakovlevdmv
86573fc414 Some improvements added. README edited 2018-04-07 18:54:57 +03:00
yakovlevdmv
4966762ce0 README editted, reutrn error if got 404 and return error in device constructor 2018-04-07 18:22:03 +03:00
yakovlevdmv
1aee7f15e3 The scopes of device functions are edited 2018-04-07 17:49:01 +03:00
George Palanjyan
ebdecc4c7f xml processing 2018-04-06 22:25:40 +03:00
yakovlevdmv
d5ca888bc4 Added Analytics datatypes. Changing namespaces prefix at struct tags 2018-04-05 06:15:00 +03:00
yakovlevdmv
d93d40283a Improvements in the package 2018-04-05 01:29:01 +03:00
George Palanjyan
68f24e5a17 merge Device 2018-04-04 22:57:16 +03:00
yakovlevdmv
25ec776ded Some improvements at Device.go. Adding WS security 2018-04-04 22:42:40 +03:00
George Palanjyan
c6ad810450 Fix bugs 2018-04-04 22:04:13 +03:00
yakovlevdmv
a72fd9bcf5 Add doc. Some improvments was made 2018-04-04 21:07:25 +03:00
George Palanjyan
95b401fbe3 Added auto check option 2018-04-04 01:22:08 +03:00