Public/Core/New-Passphrase.ps1
|
<# .SYNOPSIS Generate deterministic passphrase(s) for one or more usernames via Keysmith (SC Networks). .DESCRIPTION POSTs the nonce and username(s) to Keysmith's /api/generate endpoint and returns the generated phrase(s). Word lists stay on the server — this function never sees them. The same nonce + username + mode always yields the same phrase (deterministic), so a user's passphrase can be regenerated without storing it. One or many usernames may be supplied in a single call. The token is sent in the x-api-key header — the Static Web App proxy overwrites Authorization before it reaches the API. .PARAMETER Nonce The shared secret nonce as a SecureString. Must match the nonce configured for the tool. .PARAMETER Username One or more usernames to generate phrases for. Returns the phrase(s) in the same order. .PARAMETER Mode Generation mode: 'words' (word-word-word# style) or 'verbnoun' (verb-noun## style). Required. .PARAMETER WordCount Number of words for 'words' mode. 2-6, default 3. .PARAMETER AuthToken Keysmith API token as a SecureString authorizing the call (minted per school in the Keysmith admin UI). Throws when not supplied. .PARAMETER Rev Word-list revision to derive against. Omit to use the server's latest (normal for account creation). Pass a specific rev only to regenerate passphrases from an earlier era — the rev used is written to the log on every call. .PARAMETER FunctionUrl Base URL of the Keysmith site. Defaults to https://keysmith.scnlabs.net. .OUTPUTS [string] (or [string[]]) the generated passphrase(s). .EXAMPLE New-Passphrase -Nonce $nonce -Username 'alice' -Mode words .EXAMPLE New-Passphrase -Nonce $nonce -Username 'alice' -Mode verbnoun .EXAMPLE New-Passphrase -Nonce $nonce -Username @('alice','bob') -Mode words -WordCount 4 .NOTES Created by: Sam Cattanach Modified: 2026-06-26 #> function New-Passphrase { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [System.Security.SecureString]$Nonce, [Parameter(Mandatory = $true)] [array]$Username, [ValidateSet('words', 'verbnoun')] [Parameter(Mandatory = $true)] [string]$Mode, [ValidateRange(2, 6)] [int]$WordCount = 3, [Parameter(Mandatory = $false)] [System.Security.SecureString]$AuthToken, [ValidateRange(1, 99)] [int]$Rev, [string]$FunctionUrl = "https://keysmith.scnlabs.net" ) # ── Resolve auth token ──────────────────────────────────────────────────── if (-not $AuthToken) { throw "AuthToken is required. Pass -AuthToken as a SecureString." } $FunctionUrl = $FunctionUrl.TrimEnd('/') $GenerateUrl = "$FunctionUrl/api/generate" $Mode = $Mode.ToLower() # x-api-key is the auth header — the SWA proxy overwrites Authorization # before it reaches the API $Headers = @{ 'x-api-key' = $(ConvertFrom-SecureString $AuthToken -AsPlainText) 'Content-Type' = 'application/json' } $bodyTable = @{ nonce = $(ConvertFrom-SecureString $Nonce -AsPlainText) usernames = $Username mode = $Mode wordCount = $WordCount } if ($PSBoundParameters.ContainsKey('Rev')) { $bodyTable.rev = $Rev } $body = $bodyTable | ConvertTo-Json -Compress try { $generateParams = @{ Uri = $GenerateUrl Method = 'Post' Headers = $Headers Body = $body UseBasicParsing = $true } $generate = Invoke-RestMethod @generateParams # Record the word-list rev so logs show which era these passphrases # belong to — regeneration later needs the same nonce + rev if (Get-Command Write-Log -ErrorAction SilentlyContinue) { Write-Log -Message ("Keysmith: generated $(@($generate.results).Count) passphrase(s) — word-list rev $($generate.rev)") -Level "Info" } return $generate.results.phrase } catch { $status = $_.Exception.Response.StatusCode.value__ $detail = $_.ErrorDetails.Message throw "Function request failed (HTTP $status): $detail" } } |