b4e4982876
- Adjusted formatting in XML response strings for consistency in device_extended_test.go and device_security_test.go. - Improved readability by aligning XML declaration and body content. - Updated mock server responses to ensure proper handling of various ONVIF operations. Enhance device security and storage handling - Refactored struct field declarations in device_security.go and device_storage_test.go for improved clarity. - Ensured consistent formatting across struct definitions and XML tags. Standardize whitespace and formatting across multiple files - Removed unnecessary blank lines and adjusted indentation in discovery, imaging, media, and PTZ server files. - Improved overall code readability and maintainability by ensuring consistent formatting. Update example applications for better readability - Cleaned up whitespace in example applications to enhance code clarity. - Ensured consistent formatting in main.go files across various examples. Refactor server and SOAP handler code for consistency - Standardized struct field declarations and XML tag formatting in server and SOAP handler files. - Improved readability by aligning struct fields and ensuring consistent use of whitespace. General code cleanup and formatting adjustments - Applied consistent formatting across various files, including types.go and test files. - Enhanced readability by aligning struct fields and removing unnecessary blank lines.
429 lines
14 KiB
Go
429 lines
14 KiB
Go
package onvif
|
|
|
|
import (
|
|
"context"
|
|
"encoding/xml"
|
|
"fmt"
|
|
|
|
"github.com/0x524a/onvif-go/internal/soap"
|
|
)
|
|
|
|
// GetCertificates retrieves all certificates stored on the device.
|
|
//
|
|
// ONVIF Specification: GetCertificates operation
|
|
func (c *Client) GetCertificates(ctx context.Context) ([]*Certificate, error) {
|
|
type GetCertificatesBody struct {
|
|
XMLName xml.Name `xml:"tds:GetCertificates"`
|
|
Xmlns string `xml:"xmlns:tds,attr"`
|
|
}
|
|
|
|
type GetCertificatesResponse struct {
|
|
XMLName xml.Name `xml:"GetCertificatesResponse"`
|
|
Certificates []*Certificate `xml:"Certificate"`
|
|
}
|
|
|
|
request := GetCertificatesBody{
|
|
Xmlns: deviceNamespace,
|
|
}
|
|
var response GetCertificatesResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, c.endpoint, "", request, &response); err != nil {
|
|
return nil, fmt.Errorf("GetCertificates failed: %w", err)
|
|
}
|
|
|
|
return response.Certificates, nil
|
|
}
|
|
|
|
// GetCACertificates retrieves all CA certificates stored on the device.
|
|
//
|
|
// ONVIF Specification: GetCACertificates operation
|
|
func (c *Client) GetCACertificates(ctx context.Context) ([]*Certificate, error) {
|
|
type GetCACertificatesBody struct {
|
|
XMLName xml.Name `xml:"tds:GetCACertificates"`
|
|
Xmlns string `xml:"xmlns:tds,attr"`
|
|
}
|
|
|
|
type GetCACertificatesResponse struct {
|
|
XMLName xml.Name `xml:"GetCACertificatesResponse"`
|
|
Certificates []*Certificate `xml:"Certificate"`
|
|
}
|
|
|
|
request := GetCACertificatesBody{
|
|
Xmlns: deviceNamespace,
|
|
}
|
|
var response GetCACertificatesResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, c.endpoint, "", request, &response); err != nil {
|
|
return nil, fmt.Errorf("GetCACertificates failed: %w", err)
|
|
}
|
|
|
|
return response.Certificates, nil
|
|
}
|
|
|
|
// LoadCertificates uploads certificates to the device.
|
|
//
|
|
// ONVIF Specification: LoadCertificates operation
|
|
func (c *Client) LoadCertificates(ctx context.Context, certificates []*Certificate) error {
|
|
type LoadCertificatesBody struct {
|
|
XMLName xml.Name `xml:"tds:LoadCertificates"`
|
|
Xmlns string `xml:"xmlns:tds,attr"`
|
|
Certificate []*Certificate `xml:"tds:Certificate"`
|
|
}
|
|
|
|
type LoadCertificatesResponse struct {
|
|
XMLName xml.Name `xml:"LoadCertificatesResponse"`
|
|
}
|
|
|
|
request := LoadCertificatesBody{
|
|
Xmlns: deviceNamespace,
|
|
Certificate: certificates,
|
|
}
|
|
var response LoadCertificatesResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, c.endpoint, "", request, &response); err != nil {
|
|
return fmt.Errorf("LoadCertificates failed: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// LoadCACertificates uploads CA certificates to the device.
|
|
//
|
|
// ONVIF Specification: LoadCACertificates operation
|
|
func (c *Client) LoadCACertificates(ctx context.Context, certificates []*Certificate) error {
|
|
type LoadCACertificatesBody struct {
|
|
XMLName xml.Name `xml:"tds:LoadCACertificates"`
|
|
Xmlns string `xml:"xmlns:tds,attr"`
|
|
Certificate []*Certificate `xml:"tds:Certificate"`
|
|
}
|
|
|
|
type LoadCACertificatesResponse struct {
|
|
XMLName xml.Name `xml:"LoadCACertificatesResponse"`
|
|
}
|
|
|
|
request := LoadCACertificatesBody{
|
|
Xmlns: deviceNamespace,
|
|
Certificate: certificates,
|
|
}
|
|
var response LoadCACertificatesResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, c.endpoint, "", request, &response); err != nil {
|
|
return fmt.Errorf("LoadCACertificates failed: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// CreateCertificate creates a self-signed certificate.
|
|
//
|
|
// ONVIF Specification: CreateCertificate operation
|
|
func (c *Client) CreateCertificate(ctx context.Context, certificateID, subject string, validNotBefore, validNotAfter string) (*Certificate, error) {
|
|
type CreateCertificateBody struct {
|
|
XMLName xml.Name `xml:"tds:CreateCertificate"`
|
|
Xmlns string `xml:"xmlns:tds,attr"`
|
|
CertificateID string `xml:"tds:CertificateID,omitempty"`
|
|
Subject string `xml:"tds:Subject"`
|
|
ValidNotBefore string `xml:"tds:ValidNotBefore"`
|
|
ValidNotAfter string `xml:"tds:ValidNotAfter"`
|
|
}
|
|
|
|
type CreateCertificateResponse struct {
|
|
XMLName xml.Name `xml:"CreateCertificateResponse"`
|
|
Certificate *Certificate `xml:"Certificate"`
|
|
}
|
|
|
|
request := CreateCertificateBody{
|
|
Xmlns: deviceNamespace,
|
|
CertificateID: certificateID,
|
|
Subject: subject,
|
|
ValidNotBefore: validNotBefore,
|
|
ValidNotAfter: validNotAfter,
|
|
}
|
|
var response CreateCertificateResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, c.endpoint, "", request, &response); err != nil {
|
|
return nil, fmt.Errorf("CreateCertificate failed: %w", err)
|
|
}
|
|
|
|
return response.Certificate, nil
|
|
}
|
|
|
|
// DeleteCertificates deletes certificates from the device.
|
|
//
|
|
// ONVIF Specification: DeleteCertificates operation
|
|
func (c *Client) DeleteCertificates(ctx context.Context, certificateIDs []string) error {
|
|
type DeleteCertificatesBody struct {
|
|
XMLName xml.Name `xml:"tds:DeleteCertificates"`
|
|
Xmlns string `xml:"xmlns:tds,attr"`
|
|
CertificateID []string `xml:"tds:CertificateID"`
|
|
}
|
|
|
|
type DeleteCertificatesResponse struct {
|
|
XMLName xml.Name `xml:"DeleteCertificatesResponse"`
|
|
}
|
|
|
|
request := DeleteCertificatesBody{
|
|
Xmlns: deviceNamespace,
|
|
CertificateID: certificateIDs,
|
|
}
|
|
var response DeleteCertificatesResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, c.endpoint, "", request, &response); err != nil {
|
|
return fmt.Errorf("DeleteCertificates failed: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetCertificateInformation retrieves information about a certificate.
|
|
//
|
|
// ONVIF Specification: GetCertificateInformation operation
|
|
func (c *Client) GetCertificateInformation(ctx context.Context, certificateID string) (*CertificateInformation, error) {
|
|
type GetCertificateInformationBody struct {
|
|
XMLName xml.Name `xml:"tds:GetCertificateInformation"`
|
|
Xmlns string `xml:"xmlns:tds,attr"`
|
|
CertificateID string `xml:"tds:CertificateID"`
|
|
}
|
|
|
|
type GetCertificateInformationResponse struct {
|
|
XMLName xml.Name `xml:"GetCertificateInformationResponse"`
|
|
CertificateInformation *CertificateInformation `xml:"CertificateInformation"`
|
|
}
|
|
|
|
request := GetCertificateInformationBody{
|
|
Xmlns: deviceNamespace,
|
|
CertificateID: certificateID,
|
|
}
|
|
var response GetCertificateInformationResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, c.endpoint, "", request, &response); err != nil {
|
|
return nil, fmt.Errorf("GetCertificateInformation failed: %w", err)
|
|
}
|
|
|
|
return response.CertificateInformation, nil
|
|
}
|
|
|
|
// GetCertificatesStatus retrieves the status of certificates.
|
|
//
|
|
// ONVIF Specification: GetCertificatesStatus operation
|
|
func (c *Client) GetCertificatesStatus(ctx context.Context) ([]*CertificateStatus, error) {
|
|
type GetCertificatesStatusBody struct {
|
|
XMLName xml.Name `xml:"tds:GetCertificatesStatus"`
|
|
Xmlns string `xml:"xmlns:tds,attr"`
|
|
}
|
|
|
|
type GetCertificatesStatusResponse struct {
|
|
XMLName xml.Name `xml:"GetCertificatesStatusResponse"`
|
|
CertificateStatus []*CertificateStatus `xml:"CertificateStatus"`
|
|
}
|
|
|
|
request := GetCertificatesStatusBody{
|
|
Xmlns: deviceNamespace,
|
|
}
|
|
var response GetCertificatesStatusResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, c.endpoint, "", request, &response); err != nil {
|
|
return nil, fmt.Errorf("GetCertificatesStatus failed: %w", err)
|
|
}
|
|
|
|
return response.CertificateStatus, nil
|
|
}
|
|
|
|
// SetCertificatesStatus sets the status of certificates (enabled/disabled).
|
|
//
|
|
// ONVIF Specification: SetCertificatesStatus operation
|
|
func (c *Client) SetCertificatesStatus(ctx context.Context, statuses []*CertificateStatus) error {
|
|
type SetCertificatesStatusBody struct {
|
|
XMLName xml.Name `xml:"tds:SetCertificatesStatus"`
|
|
Xmlns string `xml:"xmlns:tds,attr"`
|
|
CertificateStatus []*CertificateStatus `xml:"tds:CertificateStatus"`
|
|
}
|
|
|
|
type SetCertificatesStatusResponse struct {
|
|
XMLName xml.Name `xml:"SetCertificatesStatusResponse"`
|
|
}
|
|
|
|
request := SetCertificatesStatusBody{
|
|
Xmlns: deviceNamespace,
|
|
CertificateStatus: statuses,
|
|
}
|
|
var response SetCertificatesStatusResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, c.endpoint, "", request, &response); err != nil {
|
|
return fmt.Errorf("SetCertificatesStatus failed: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetPkcs10Request generates a PKCS#10 certificate signing request.
|
|
//
|
|
// ONVIF Specification: GetPkcs10Request operation
|
|
func (c *Client) GetPkcs10Request(ctx context.Context, certificateID, subject string, attributes *BinaryData) (*BinaryData, error) {
|
|
type GetPkcs10RequestBody struct {
|
|
XMLName xml.Name `xml:"tds:GetPkcs10Request"`
|
|
Xmlns string `xml:"xmlns:tds,attr"`
|
|
CertificateID string `xml:"tds:CertificateID,omitempty"`
|
|
Subject string `xml:"tds:Subject"`
|
|
Attributes *BinaryData `xml:"tds:Attributes,omitempty"`
|
|
}
|
|
|
|
type GetPkcs10RequestResponse struct {
|
|
XMLName xml.Name `xml:"GetPkcs10RequestResponse"`
|
|
Pkcs10Request *BinaryData `xml:"Pkcs10Request"`
|
|
}
|
|
|
|
request := GetPkcs10RequestBody{
|
|
Xmlns: deviceNamespace,
|
|
CertificateID: certificateID,
|
|
Subject: subject,
|
|
Attributes: attributes,
|
|
}
|
|
var response GetPkcs10RequestResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, c.endpoint, "", request, &response); err != nil {
|
|
return nil, fmt.Errorf("GetPkcs10Request failed: %w", err)
|
|
}
|
|
|
|
return response.Pkcs10Request, nil
|
|
}
|
|
|
|
// LoadCertificateWithPrivateKey uploads a certificate with its private key.
|
|
//
|
|
// ONVIF Specification: LoadCertificateWithPrivateKey operation
|
|
func (c *Client) LoadCertificateWithPrivateKey(ctx context.Context, certificates []*Certificate, privateKey []*BinaryData, certificateIDs []string) error {
|
|
type LoadCertificateWithPrivateKeyBody struct {
|
|
XMLName xml.Name `xml:"tds:LoadCertificateWithPrivateKey"`
|
|
Xmlns string `xml:"xmlns:tds,attr"`
|
|
CertificateWithPrivateKey []struct {
|
|
CertificateID string `xml:"CertificateID"`
|
|
Certificate *Certificate `xml:"Certificate"`
|
|
PrivateKey *BinaryData `xml:"PrivateKey"`
|
|
} `xml:"tds:CertificateWithPrivateKey"`
|
|
}
|
|
|
|
type LoadCertificateWithPrivateKeyResponse struct {
|
|
XMLName xml.Name `xml:"LoadCertificateWithPrivateKeyResponse"`
|
|
}
|
|
|
|
request := LoadCertificateWithPrivateKeyBody{
|
|
Xmlns: deviceNamespace,
|
|
}
|
|
|
|
// Build certificate with private key array
|
|
for i := 0; i < len(certificates); i++ {
|
|
item := struct {
|
|
CertificateID string `xml:"CertificateID"`
|
|
Certificate *Certificate `xml:"Certificate"`
|
|
PrivateKey *BinaryData `xml:"PrivateKey"`
|
|
}{
|
|
CertificateID: certificateIDs[i],
|
|
Certificate: certificates[i],
|
|
}
|
|
if i < len(privateKey) {
|
|
item.PrivateKey = privateKey[i]
|
|
}
|
|
request.CertificateWithPrivateKey = append(request.CertificateWithPrivateKey, item)
|
|
}
|
|
|
|
var response LoadCertificateWithPrivateKeyResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, c.endpoint, "", request, &response); err != nil {
|
|
return fmt.Errorf("LoadCertificateWithPrivateKey failed: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetClientCertificateMode retrieves the client certificate authentication mode.
|
|
//
|
|
// ONVIF Specification: GetClientCertificateMode operation
|
|
func (c *Client) GetClientCertificateMode(ctx context.Context) (bool, error) {
|
|
type GetClientCertificateModeBody struct {
|
|
XMLName xml.Name `xml:"tds:GetClientCertificateMode"`
|
|
Xmlns string `xml:"xmlns:tds,attr"`
|
|
}
|
|
|
|
type GetClientCertificateModeResponse struct {
|
|
XMLName xml.Name `xml:"GetClientCertificateModeResponse"`
|
|
Enabled bool `xml:"Enabled"`
|
|
}
|
|
|
|
request := GetClientCertificateModeBody{
|
|
Xmlns: deviceNamespace,
|
|
}
|
|
var response GetClientCertificateModeResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, c.endpoint, "", request, &response); err != nil {
|
|
return false, fmt.Errorf("GetClientCertificateMode failed: %w", err)
|
|
}
|
|
|
|
return response.Enabled, nil
|
|
}
|
|
|
|
// SetClientCertificateMode sets the client certificate authentication mode.
|
|
//
|
|
// ONVIF Specification: SetClientCertificateMode operation
|
|
func (c *Client) SetClientCertificateMode(ctx context.Context, enabled bool) error {
|
|
type SetClientCertificateModeBody struct {
|
|
XMLName xml.Name `xml:"tds:SetClientCertificateMode"`
|
|
Xmlns string `xml:"xmlns:tds,attr"`
|
|
Enabled bool `xml:"tds:Enabled"`
|
|
}
|
|
|
|
type SetClientCertificateModeResponse struct {
|
|
XMLName xml.Name `xml:"SetClientCertificateModeResponse"`
|
|
}
|
|
|
|
request := SetClientCertificateModeBody{
|
|
Xmlns: deviceNamespace,
|
|
Enabled: enabled,
|
|
}
|
|
var response SetClientCertificateModeResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, c.endpoint, "", request, &response); err != nil {
|
|
return fmt.Errorf("SetClientCertificateMode failed: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|