Skip to content

Commit f177577

Browse files
Merge PR #14 Domeneshop API capabilities
2 parents 311f50a + e142777 commit f177577

21 files changed

Lines changed: 791 additions & 3 deletions
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
function Get-DomeneshopConfig {
2+
[CmdletBinding()]
3+
param()
4+
5+
$vault = 'Domeneshop'
6+
$id = '__Domeneshop.Config'
7+
$config = Get-Context -ID $id -Vault $vault -ErrorAction SilentlyContinue
8+
9+
if (-not $config) {
10+
$config = [ordered]@{
11+
DefaultContext = $null
12+
ApiBaseUri = 'https://api.domeneshop.no/v0'
13+
}
14+
Set-Context -ID $id -Vault $vault -Context $config
15+
$config = Get-Context -ID $id -Vault $vault
16+
}
17+
18+
$config
19+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
function Resolve-DomeneshopContext {
2+
[CmdletBinding()]
3+
param(
4+
[Parameter()]
5+
[string] $Context
6+
)
7+
8+
$resolvedContext = if ($Context) {
9+
Get-DomeneshopContext -Context $Context
10+
} else {
11+
Get-DomeneshopContext
12+
}
13+
14+
if (-not $resolvedContext) {
15+
throw "No Domeneshop context found. Run 'Connect-DomeneshopAccount' first."
16+
}
17+
18+
if ([string]::IsNullOrEmpty($resolvedContext.Token) -or -not ($resolvedContext.Secret -is [securestring])) {
19+
throw "The Domeneshop context [$($resolvedContext.ID)] is missing valid credentials."
20+
}
21+
22+
$resolvedContext
23+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
function Set-DomeneshopDefaultContext {
2+
[CmdletBinding()]
3+
param(
4+
[Parameter(Mandatory)]
5+
[string] $Context
6+
)
7+
8+
$config = Get-DomeneshopConfig
9+
$config.DefaultContext = $Context
10+
Set-Context -ID '__Domeneshop.Config' -Vault 'Domeneshop' -Context $config
11+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
function Get-DomeneshopApiBaseUri {
2+
[CmdletBinding()]
3+
param(
4+
[Parameter(Mandatory)]
5+
[object] $Context
6+
)
7+
8+
$apiBaseUri = [string] $Context.ApiBaseUri
9+
if ([string]::IsNullOrEmpty($apiBaseUri)) {
10+
$apiBaseUri = 'https://api.domeneshop.no/v0'
11+
}
12+
13+
$apiBaseUri.TrimEnd('/')
14+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
function Invoke-DomeneshopApiRequest {
2+
[CmdletBinding()]
3+
param(
4+
[Parameter(Mandatory)]
5+
[ValidateSet('Get', 'Post', 'Put', 'Delete')]
6+
[string] $Method,
7+
8+
[Parameter(Mandatory)]
9+
[string] $Uri,
10+
11+
[Parameter(Mandatory)]
12+
[object] $Context,
13+
14+
[Parameter()]
15+
[AllowNull()]
16+
[object] $Body
17+
)
18+
19+
$credential = [pscredential]::new(
20+
[string] $Context.Token,
21+
[securestring] $Context.Secret
22+
)
23+
24+
$params = @{
25+
Method = $Method
26+
Uri = $Uri
27+
Authentication = 'Basic'
28+
Credential = $credential
29+
}
30+
31+
if ($PSBoundParameters.ContainsKey('Body')) {
32+
$params['ContentType'] = 'application/json'
33+
$params['Body'] = ($Body | ConvertTo-Json -Depth 100)
34+
}
35+
36+
Invoke-RestMethod @params
37+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
function Connect-DomeneshopAccount {
2+
<#
3+
.SYNOPSIS
4+
Stores Domeneshop API credentials in a secure context.
5+
6+
.DESCRIPTION
7+
Stores Domeneshop API credentials using the Context module and optionally sets the context as default.
8+
9+
.EXAMPLE
10+
Connect-DomeneshopAccount -Token 'my-token' -Secret (Read-Host -AsSecureString)
11+
#>
12+
[OutputType([object])]
13+
[CmdletBinding()]
14+
param(
15+
[Parameter(Mandatory)]
16+
[string] $Token,
17+
18+
[Parameter(Mandatory)]
19+
[object] $Secret,
20+
21+
[Parameter()]
22+
[string] $Context = 'default',
23+
24+
[Parameter()]
25+
[switch] $Default,
26+
27+
[Parameter()]
28+
[switch] $PassThru
29+
)
30+
31+
$secureSecret = switch ($Secret) {
32+
{ $_ -is [securestring] } { $_; break }
33+
{ $_ -is [string] } { ConvertTo-SecureString -AsPlainText $Secret -Force; break }
34+
default { throw 'Secret must be a SecureString or String value.' }
35+
}
36+
37+
$contextObject = [ordered]@{
38+
Name = $Context
39+
Token = $Token
40+
Secret = $secureSecret
41+
AuthType = 'BasicAuth'
42+
ApiBaseUri = 'https://api.domeneshop.no/v0'
43+
ConnectedAt = Get-Date
44+
}
45+
46+
Set-Context -ID $Context -Vault 'Domeneshop' -Context $contextObject
47+
48+
$config = Get-DomeneshopConfig
49+
if ($Default -or [string]::IsNullOrEmpty($config.DefaultContext)) {
50+
Set-DomeneshopDefaultContext -Context $Context
51+
}
52+
53+
if ($PassThru) {
54+
Get-DomeneshopContext -Context $Context
55+
}
56+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
function Get-DomeneshopContext {
2+
<#
3+
.SYNOPSIS
4+
Gets stored Domeneshop contexts.
5+
6+
.DESCRIPTION
7+
Returns one or more contexts stored in the Domeneshop context vault.
8+
9+
.EXAMPLE
10+
Get-DomeneshopContext
11+
#>
12+
[OutputType([object])]
13+
[CmdletBinding(DefaultParameterSetName = 'GetDefault')]
14+
param(
15+
[Parameter(Mandatory, ParameterSetName = 'GetNamed')]
16+
[string] $Context,
17+
18+
[Parameter(Mandatory, ParameterSetName = 'ListAvailable')]
19+
[switch] $ListAvailable
20+
)
21+
22+
$id = switch ($PSCmdlet.ParameterSetName) {
23+
'GetNamed' { $Context; break }
24+
'ListAvailable' { '*'; break }
25+
default {
26+
$config = Get-DomeneshopConfig
27+
if ([string]::IsNullOrEmpty($config.DefaultContext)) {
28+
throw "No default Domeneshop context found. Run 'Connect-DomeneshopAccount' first."
29+
}
30+
$config.DefaultContext
31+
}
32+
}
33+
34+
Get-Context -ID $id -Vault 'Domeneshop' | Where-Object { $_.ID -ne '__Domeneshop.Config' } | Sort-Object -Property ID
35+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
function Update-DomeneshopDdns {
2+
<#
3+
.SYNOPSIS
4+
Updates dynamic DNS for a hostname.
5+
6+
.DESCRIPTION
7+
Calls the Domeneshop DDNS update endpoint. The API creates the A/AAAA record if it does not exist.
8+
#>
9+
[OutputType([object])]
10+
[CmdletBinding()]
11+
param(
12+
[Parameter(Mandatory)]
13+
[Alias('Host')]
14+
[string] $Hostname,
15+
16+
[Parameter()]
17+
[Alias('IP')]
18+
[string] $MyIP,
19+
20+
[Parameter()]
21+
[string] $Context
22+
)
23+
24+
$resolvedContext = Resolve-DomeneshopContext -Context $Context
25+
$apiBaseUri = Get-DomeneshopApiBaseUri -Context $resolvedContext
26+
$uri = "$apiBaseUri/dyndns/update?hostname=$([uri]::EscapeDataString($Hostname))"
27+
if ($PSBoundParameters.ContainsKey('MyIP')) {
28+
$uri = "$uri&myip=$([uri]::EscapeDataString($MyIP))"
29+
}
30+
31+
Invoke-DomeneshopApiRequest -Method Get -Uri $uri -Context $resolvedContext
32+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
function Add-DomeneshopDnsRecord {
2+
<#
3+
.SYNOPSIS
4+
Adds a DNS record to a Domeneshop domain.
5+
#>
6+
[OutputType([object])]
7+
[CmdletBinding()]
8+
param(
9+
[Parameter(Mandatory)]
10+
[int] $DomainID,
11+
12+
[Parameter(Mandatory)]
13+
[object] $Record,
14+
15+
[Parameter()]
16+
[string] $Context
17+
)
18+
19+
$resolvedContext = Resolve-DomeneshopContext -Context $Context
20+
$apiBaseUri = Get-DomeneshopApiBaseUri -Context $resolvedContext
21+
$uri = "$apiBaseUri/domains/$DomainID/dns"
22+
23+
Invoke-DomeneshopApiRequest -Method Post -Uri $uri -Context $resolvedContext -Body $Record
24+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
function Get-DomeneshopDnsRecord {
2+
<#
3+
.SYNOPSIS
4+
Gets DNS records for a Domeneshop domain.
5+
6+
.DESCRIPTION
7+
Lists DNS records for a domain, or gets one DNS record by ID.
8+
#>
9+
[OutputType([object[]])]
10+
[CmdletBinding(DefaultParameterSetName = 'List')]
11+
param(
12+
[Parameter(Mandatory)]
13+
[int] $DomainID,
14+
15+
[Parameter(Mandatory, ParameterSetName = 'GetByID')]
16+
[int] $RecordID,
17+
18+
[Parameter(ParameterSetName = 'List')]
19+
[Alias('Host')]
20+
[string] $RecordHost,
21+
22+
[Parameter(ParameterSetName = 'List')]
23+
[string] $Type,
24+
25+
[Parameter(ParameterSetName = 'List')]
26+
[string] $Data,
27+
28+
[Parameter()]
29+
[string] $Context
30+
)
31+
32+
$resolvedContext = Resolve-DomeneshopContext -Context $Context
33+
$apiBaseUri = Get-DomeneshopApiBaseUri -Context $resolvedContext
34+
$uri = "$apiBaseUri/domains/$DomainID/dns"
35+
36+
if ($PSCmdlet.ParameterSetName -eq 'GetByID') {
37+
$uri = "$uri/$RecordID"
38+
} else {
39+
$queryParts = @()
40+
if ($PSBoundParameters.ContainsKey('RecordHost')) {
41+
$queryParts += "host=$([uri]::EscapeDataString($RecordHost))"
42+
}
43+
if ($PSBoundParameters.ContainsKey('Type')) {
44+
$queryParts += "type=$([uri]::EscapeDataString($Type))"
45+
}
46+
if ($PSBoundParameters.ContainsKey('Data')) {
47+
$queryParts += "data=$([uri]::EscapeDataString($Data))"
48+
}
49+
if ($queryParts.Count -gt 0) {
50+
$uri = "${uri}?{0}" -f ($queryParts -join '&')
51+
}
52+
}
53+
54+
Invoke-DomeneshopApiRequest -Method Get -Uri $uri -Context $resolvedContext
55+
}

0 commit comments

Comments
 (0)