Skip to content

Commit 494c0a1

Browse files
committed
Initial commit
0 parents  commit 494c0a1

12 files changed

+230
-0
lines changed

.github/workflows/release.yml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name: Publish Module
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
publish-module:
8+
name: Publish Module
9+
uses: PowerShellLibrary/.github/.github/workflows/publish-module.yml@master
10+
secrets: inherit
11+

.github/workflows/test.yml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name: Invoke Pester Tests
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches:
7+
- master
8+
9+
jobs:
10+
invoke-pester:
11+
uses: PowerShellLibrary/.github/.github/workflows/invoke-pester.yml@master

LICENSE

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Alan Płócieniak
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6+
7+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8+
9+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# CRX
2+
3+
Module for downloading CRX (extension package) for Chromium-based browsers.

src/CRX.psd1

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
@{
3+
RootModule = 'CRX.psm1'
4+
ModuleVersion = '0.1.0'
5+
GUID = 'b5433b6c-b423-4049-8c5e-b3a50566fcf2'
6+
Author = 'Alan Plocieniak'
7+
CompanyName = 'Alan Plocieniak'
8+
Copyright = '(c) 2025 Alan Plocieniak. All rights reserved.'
9+
Description = 'Module for downloading CRX (extension package) for Chromium-based browsers.'
10+
PowerShellVersion = '5.1'
11+
CompatiblePSEditions = 'Desktop', 'Core'
12+
FunctionsToExport = '*'
13+
PrivateData = @{
14+
PSData = @{
15+
}
16+
}
17+
}

src/CRX.psm1

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
$Public = @( Get-ChildItem -Path $PSScriptRoot\Public -Recurse -Filter *.ps1 -ErrorAction SilentlyContinue )
2+
$Private = @( Get-ChildItem -Path $PSScriptRoot\Private -Recurse -Filter *.ps1 -ErrorAction SilentlyContinue )
3+
4+
Foreach ($import in @($Public + $Private)) {
5+
try {
6+
. $import.fullname
7+
}
8+
catch {
9+
Write-Error -Message "Failed to import function $($import.fullname): $_"
10+
}
11+
}
12+
Export-ModuleMember -Function $Public.Basename

src/Private/CRXUpdateInfo.ps1

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class CRXUpdateInfo {
2+
[string]$Version
3+
[string]$Url
4+
[string]$SHA256
5+
[string]$Status
6+
[int]$Size
7+
8+
CRXUpdateInfo($obj) {
9+
$this.Version = $obj.version
10+
$this.Url = $obj.codebase
11+
$this.SHA256 = $obj.hash_sha256
12+
$this.Status = $obj.status
13+
$this.Size = $obj.size
14+
}
15+
}

src/Private/Get-CRXUpdateUrl.ps1

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
function Get-CRXUpdateUrl {
2+
param (
3+
[Parameter(Mandatory = $true)]
4+
[string]$Id
5+
)
6+
7+
"https://clients2.google.com/service/update2/crx?prodversion=131.0.6778.205&acceptformat=crx2,crx3&x=id%3D$Id%26installsource%3Dondemand%26uc"
8+
}

src/Public/Get-CRX.ps1

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
function Get-CRX {
2+
[CmdletBinding()]
3+
param (
4+
[Parameter(Mandatory = $true)]
5+
[string]$Id,
6+
7+
[Parameter(Mandatory = $true)]
8+
[string]$OutputDirectory
9+
)
10+
11+
$info = Get-CRXUpdateInfo -Id $Id
12+
try {
13+
$outputPath = Join-Path -Path $OutputDirectory -ChildPath (Split-Path -Leaf $info.Url)
14+
Invoke-WebRequest -Uri $info.Url -OutFile $outputPath
15+
Get-Item -Path $outputPath
16+
}
17+
catch {
18+
Write-Error $_.Exception.Message
19+
}
20+
}

src/Public/Get-CRXUpdateInfo.ps1

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
function Get-CRXUpdateInfo {
2+
[CmdletBinding()]
3+
param (
4+
[Parameter(Mandatory = $true)]
5+
[string]$Id
6+
)
7+
8+
$url = Get-CRXUpdateUrl -Id $Id
9+
try {
10+
$update = Invoke-RestMethod -Uri $url
11+
$app = $update.gupdate.app
12+
if ($app -and $app.updatecheck) {
13+
return [CRXUpdateInfo]::new($app.updatecheck)
14+
}
15+
}
16+
catch {
17+
Write-Error $_.Exception.Message
18+
}
19+
return $null
20+
}
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
function Test-CRXUpdateAvailable {
2+
[CmdletBinding()]
3+
param (
4+
[Parameter(Mandatory = $true)]
5+
[string]$Id,
6+
7+
[Parameter(Mandatory = $true)]
8+
[version]$currentVersion
9+
)
10+
11+
$updateInfo = Get-CRXUpdateInfo $Id
12+
if ($updateInfo) {
13+
$updateVersion = [version]$updateInfo.Version
14+
return $updateVersion -gt $currentVersion
15+
}
16+
else {
17+
return $false
18+
}
19+
}

tests/CRX.Tests.ps1

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
Clear-Host
2+
if (-not (Get-Module -Name Pester)) {
3+
Import-Module -Name Pester -Force
4+
}
5+
Import-Module .\src\CRX.psm1 -Force
6+
7+
Describe 'CRX.Tests' {
8+
Context 'Get-CRXUpdateInfo' {
9+
It 'Should return CRXUpdateInfo object' {
10+
$response = Get-CRXUpdateInfo "aoclhcccfdkjddgpaaajldgljhllhgmd"
11+
$response.Url | Should -Not -BeNullOrEmpty
12+
$response.Version | Should -Not -BeNullOrEmpty
13+
}
14+
15+
It 'Should return null for invalid extension ID' {
16+
$response = Get-CRXUpdateInfo "invalid"
17+
$response | Should -BeNullOrEmpty
18+
}
19+
}
20+
21+
Context 'Test-CRXUpdateAvailable' {
22+
It 'Should return true if update is available' {
23+
Mock -CommandName Get-CRXUpdateInfo -ModuleName CRX -MockWith {
24+
return [PSCustomObject]@{
25+
Version = "2.0.0"
26+
Url = "http://example.com"
27+
SHA256 = "dummyhash"
28+
Status = "ok"
29+
Size = 12345
30+
}
31+
}
32+
$result = Test-CRXUpdateAvailable -Id "aoclhcccfdkjddgpaaajldgljhllhgmd" -currentVersion "1.0.0"
33+
$result | Should -Be $true
34+
}
35+
36+
It 'Should return false if no update is available' {
37+
Mock -CommandName Get-CRXUpdateInfo -ModuleName CRX -MockWith {
38+
return [PSCustomObject]@{
39+
Version = "1.0.0"
40+
Url = "http://example.com"
41+
SHA256 = "dummyhash"
42+
Status = "ok"
43+
Size = 12345
44+
}
45+
}
46+
$result = Test-CRXUpdateAvailable -Id "aoclhcccfdkjddgpaaajldgljhllhgmd" -currentVersion "1.0.0"
47+
$result | Should -Be $false
48+
}
49+
50+
It 'Should return false if update info is null' {
51+
Mock -CommandName Get-CRXUpdateInfo -ModuleName CRX -MockWith { return $null }
52+
$result = Test-CRXUpdateAvailable -Id "aoclhcccfdkjddgpaaajldgljhllhgmd" -currentVersion "1.0.0"
53+
$result | Should -Be $false
54+
}
55+
}
56+
57+
Context 'Get-CRX' {
58+
It 'Should download CRX file to specified directory' {
59+
Mock -CommandName Get-CRXUpdateInfo -ModuleName CRX -MockWith {
60+
return [PSCustomObject]@{
61+
Version = "2.0.0"
62+
Url = "http://example.com/extension.crx"
63+
SHA256 = "dummyhash"
64+
Status = "ok"
65+
Size = 12345
66+
}
67+
}
68+
69+
Mock -CommandName Invoke-WebRequest -ModuleName CRX -MockWith {
70+
param ($Uri, $OutFile)
71+
New-Item -ItemType File -Path $OutFile -Force | Out-Null
72+
}
73+
74+
$outputDir = ".\temp"
75+
$result = Get-CRX -Id "aoclhcccfdkjddgpaaajldgljhllhgmd" -OutputDirectory $outputDir
76+
77+
$expectedPath = Join-Path -Path $outputDir -ChildPath "extension.crx"
78+
Test-Path $expectedPath | Should -Be $true
79+
$result | Should -BeOfType [System.IO.FileInfo]
80+
$result.FullName | Should -Be (Resolve-Path $expectedPath | Select-Object -ExpandProperty Path)
81+
82+
Remove-Item -Path $outputDir -Recurse -Force
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)