Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 43 additions & 19 deletions src/private/AuthWebServer.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,60 @@ Function Wait-GoogleAuthApiToken
$HttpListener.Start()

$authCodeReceived = $False

while ($HttpListener.IsListening -and -not $authCodeReceived) {
$HttpContext = $HttpListener.GetContext()
$HttpRequest = $HttpContext.Request
$Query = $HttpRequest.QueryString
# Use async method with timeout to allow for cancellation
$contextTask = $HttpListener.GetContextAsync()

# Wait for either a request or cancellation (check every 500ms)
while (-not $contextTask.IsCompleted) {
Start-Sleep -Milliseconds 500

# Check if user pressed Ctrl+C by testing if we can write to console
try {
[Console]::TreatControlCAsInput = $false
if ([Console]::KeyAvailable) {
$key = [Console]::ReadKey($true)
if ($key.Key -eq 'C' -and $key.Modifiers -eq 'Control') {
Write-Information "`nCancellation requested. Stopping auth server..."
return $null
}
}
}
catch {
# Ignore console access errors
}
}

if ($contextTask.IsCompleted) {
$HttpContext = $contextTask.Result
$HttpRequest = $HttpContext.Request
$Query = $HttpRequest.QueryString

if ($null -ne $Query["code"]) {
$authCode = $Query["code"]
Write-Output $authCode
Write-Verbose "Received auth-code: $authCode"
$authCodeReceived = $true
if ($null -ne $Query["code"]) {
$authCode = $Query["code"]
Write-Output $authCode
Write-Verbose "Received auth-code: $authCode"
$authCodeReceived = $true

# Send "Thanks!"
$buffer = [System.Text.Encoding]::UTF8.GetBytes("<html><body>Good Job! Successfully authorized PSBlogger. You can close this browser window now.</body></html>")
$response = $HttpContext.Response
$response.ContentLength64 = $buffer.Length
$output = $response.OutputStream;
$output.Write($buffer,0,$buffer.Length)
$output.Close() | Write-Verbose
}
# Send "Thanks!"
$buffer = [System.Text.Encoding]::UTF8.GetBytes("<html><body>Good Job! Successfully authorized PSBlogger. You can close this browser window now.</body></html>")
$response = $HttpContext.Response
$response.ContentLength64 = $buffer.Length
$output = $response.OutputStream;
$output.Write($buffer,0,$buffer.Length)
$output.Close() | Write-Verbose
}
}
}

Write-Verbose "Stopping HttpListener."
$HttpListener.Stop()
Write-Verbose "Stopped HttpListener."
}
catch {
# TODO: Catch Permission denied error and warn about running from an elevated prompt
# or add Requires -Administrator
Write-Error $_.ToString()
Write-Error $_.ToString() -ErrorAction Stop
}
finally {
if ($null -ne $HttpListener) {
Expand Down
43 changes: 31 additions & 12 deletions src/public/Initialize-Blogger.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
This prepares your system to use Pandoc + Blogger together by obtaining an authtoken that is
authorized to communicate with blogger.

.PARAMETER clientId
.PARAMETER ClientId
Google API Client ID. This currently defaults to the one I use, but you
will need to create your own until the Google Application is published and verified

.PARAMETER clientSecret
.PARAMETER ClientSecret
Google API Client Secret. A default value is provided, but you can provide your own if you don't trust me.

.PARAMETER redirectUri
.PARAMETER RedirectUri
The oAuth redirect URL specifed in the Google API Consent Form.

.EXAMPLE
Expand All @@ -23,45 +23,64 @@ Initiate a login flow with Google

#>
Function Initialize-Blogger {
[CmdletBinding()]
Param(
[Parameter(HelpMessage = "Google API ClientId")]
[string]$clientId = "<<CLIENT_ID>>",
[string]$ClientId = "<<CLIENT_ID>>",

[Parameter(HelpMessage = "Google API Client Secret")]
[string]$clientSecret = "<<CLIENT_SECRET>>",
[string]$ClientSecret = "<<CLIENT_SECRET>>",

[Parameter(HelpMessage = "Redirect Uri specified in Google API Consent Form")]
[string]$redirectUri = "http://localhost/oauth2callback"
[string]$RedirectUri = "http://localhost/oauth2callback"
)

$ErrorActionPreference = 'Stop'
if ($env:PSBLOGGER_CLIENT_ID -and !$PSBoundParameters.ContainsKey("ClientId"))
{
Write-Verbose "Using environment variable PSBLOGGER_CLIENT_ID for ClientId"
$ClientId = $env:PSBLOGGER_CLIENT_ID
}
if ($env:PSBLOGGER_CLIENT_SECRET -and !$PSBoundParameters.ContainsKey("ClientSecret"))
{
Write-Verbose "Using environment variable PSBLOGGER_CLIENT_SECRET for ClientSecret"
$ClientSecret = $env:PSBLOGGER_CLIENT_SECRET
}
if ($ClientId -eq "<<CLIENT_ID>>" -or $ClientSecret -eq "<<CLIENT_SECRET>>") {
Write-Error "See contribution guide for how to set up your own Google API for local development."
return
}

Write-Information "Let's get an auth-code."

# specify the scopes we want in our auth token
$scope = @(
"https://www.googleapis.com/auth/blogger"
"https://www.googleapis.com/auth/drive.file"

) -join " "

$url = "https://accounts.google.com/o/oauth2/auth?client_id=$clientId&scope=$scope&response_type=code&redirect_uri=$redirectUri&access_type=offline&approval_prompt=force"
$url = "https://accounts.google.com/o/oauth2/auth?client_id=$ClientId&scope=$scope&response_type=code&redirect_uri=$RedirectUri&access_type=offline&approval_prompt=force"

Start-Process $url

$code = Wait-GoogleAuthApiToken

if ($null -eq $code) {
Write-Information "Authentication cancelled by user."
return
}

Write-Information "Sucessfully obtained auth-code!"


# trade the auth-code for an token that has a short-lived expiry
$expiringToken = Get-GoogleAccessToken -clientId $clientId -clientSecret $clientSecret -redirectUri $redirectUri -code $code
$expiringToken = Get-GoogleAccessToken -clientId $ClientId -clientSecret $ClientSecret -redirectUri $RedirectUri -code $code

# use the refresh-token to get an updated access-token
$token = Update-GoogleAccessToken -clientId $clientId -clientSecret $clientSecret -refreshToken $expiringToken.refresh_token
$token = Update-GoogleAccessToken -clientId $ClientId -clientSecret $ClientSecret -refreshToken $expiringToken.refresh_token

# save the token in the credential_cache.json
Set-CredentialCache -clientId $clientId -clientSecret $clientSecret -refreshToken $expiringToken -token $token
Set-CredentialCache -clientId $ClientId -clientSecret $ClientSecret -refreshToken $expiringToken -token $token

Write-Information "Awesome. We're all set."
}
16 changes: 12 additions & 4 deletions src/tests/Initialize-Blogger.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,13 @@ Describe "Initialize-Blogger" {
# arrange
$credentialCache = "TestDrive:\credentialcache.json"
$BloggerSession.CredentialCache = $credentialCache

$initArgs = @{
ClientId = "dummy"
ClientSecret = "dummy"
}

# act
Initialize-Blogger
Initialize-Blogger @initArgs

# assert
$credentials = Get-Content -Path $credentialCache | ConvertFrom-Json
Expand All @@ -53,9 +56,14 @@ Describe "Initialize-Blogger" {
$BloggerSession.AccessToken = "invalid"
$BloggerSession.RefreshToken = "invalid"

$initArgs = @{
ClientId = "dummy"
ClientSecret = "dummy"
}

# act
Initialize-Blogger
Initialize-Blogger @initArgs

# assert
$BloggerSession.AccessToken | Should -Be $null
$BloggerSession.RefreshToken | Should -Be $null
Expand Down
Loading