├── .editorconfig ├── .github ├── CODEOWNERS ├── dependabot.yml ├── labels.yml └── workflows │ ├── build.yml │ ├── labels.yml │ └── released.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── assets └── assets.go ├── build.properties ├── build.xml ├── go.mod ├── go.sum ├── main.go ├── mozlz4.go ├── res ├── FirefoxDeveloperEdition.lnk ├── app.ico ├── papp.ico ├── papp.manifest ├── papp.png ├── run.iss └── setup-mini.bmp └── tools └── tools.go /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs. 2 | # More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_size = 2 9 | indent_style = space 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | 17 | [*.go] 18 | indent_style = tab 19 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @crazy-max 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gomod" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | time: "08:00" 8 | timezone: "Europe/Paris" 9 | labels: 10 | - ":game_die: dependencies" 11 | - ":robot: bot" 12 | - package-ecosystem: "github-actions" 13 | directory: "/" 14 | schedule: 15 | interval: "daily" 16 | time: "08:00" 17 | timezone: "Europe/Paris" 18 | labels: 19 | - ":game_die: dependencies" 20 | - ":robot: bot" 21 | -------------------------------------------------------------------------------- /.github/labels.yml: -------------------------------------------------------------------------------- 1 | ## more info https://github.com/crazy-max/ghaction-github-labeler 2 | - # bot 3 | name: ":robot: bot" 4 | color: "69cde9" 5 | description: "" 6 | - # broken 7 | name: ":zap: broken" 8 | color: "a3090e" 9 | description: "" 10 | - # bug 11 | name: ":bug: bug" 12 | color: "b60205" 13 | description: "" 14 | - # dependencies 15 | name: ":game_die: dependencies" 16 | color: "0366d6" 17 | description: "" 18 | - # documentation 19 | name: ":memo: documentation" 20 | color: "c5def5" 21 | description: "" 22 | - # duplicate 23 | name: ":busts_in_silhouette: duplicate" 24 | color: "cccccc" 25 | description: "" 26 | - # enhancement 27 | name: ":sparkles: enhancement" 28 | color: "0054ca" 29 | description: "" 30 | - # feature request 31 | name: ":bulb: feature request" 32 | color: "0e8a16" 33 | description: "" 34 | - # feedback 35 | name: ":mega: feedback" 36 | color: "03a9f4" 37 | description: "" 38 | - # future maybe 39 | name: ":rocket: future maybe" 40 | color: "fef2c0" 41 | description: "" 42 | - # good first issue 43 | name: ":hatching_chick: good first issue" 44 | color: "7057ff" 45 | description: "" 46 | - # help wanted 47 | name: ":pray: help wanted" 48 | color: "4caf50" 49 | description: "" 50 | - # hold 51 | name: ":hand: hold" 52 | color: "24292f" 53 | description: "" 54 | - # invalid 55 | name: ":no_entry_sign: invalid" 56 | color: "e6e6e6" 57 | description: "" 58 | - # maybe bug 59 | name: ":interrobang: maybe bug" 60 | color: "ff5722" 61 | description: "" 62 | - # needs more info 63 | name: ":thinking: needs more info" 64 | color: "795548" 65 | description: "" 66 | - # question 67 | name: ":question: question" 68 | color: "3f51b5" 69 | description: "" 70 | - # trademark violation 71 | name: ":construction: trademark violation" 72 | color: "cfe524" 73 | description: "" 74 | - # upstream 75 | name: ":eyes: upstream" 76 | color: "fbca04" 77 | description: "" 78 | - # wontfix 79 | name: ":coffin: wontfix" 80 | color: "ffffff" 81 | description: "" 82 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | tags: 7 | - '*' 8 | pull_request: 9 | 10 | jobs: 11 | build: 12 | uses: portapps/.github/.github/workflows/app-build.yml@master 13 | -------------------------------------------------------------------------------- /.github/workflows/labels.yml: -------------------------------------------------------------------------------- 1 | name: labels 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | paths: 8 | - '.github/labels.yml' 9 | - '.github/workflows/labels.yml' 10 | 11 | jobs: 12 | labeler: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - 16 | name: Checkout 17 | uses: actions/checkout@v4 18 | - 19 | name: Run Labeler 20 | uses: crazy-max/ghaction-github-labeler@v5 21 | -------------------------------------------------------------------------------- /.github/workflows/released.yml: -------------------------------------------------------------------------------- 1 | name: released 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | virustotal: 9 | uses: portapps/.github/.github/workflows/app-virustotal.yml@master 10 | secrets: 11 | vt_api_key: ${{ secrets.VT_API_KEY }} 12 | vt_monitor_api_key: ${{ secrets.VT_MONITOR_API_KEY }} 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Intellij 2 | /.idea 3 | /*.iml 4 | 5 | # App 6 | /.dev 7 | /bin 8 | /vendor 9 | /*.syso 10 | /*.exe 11 | /versioninfo.json 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 138.0b3-52 (2025/04/06) 4 | 5 | * Firefox Developer Edition 138.0b3 6 | * Portapps 3.16.0 7 | 8 | ## 133.0b7-51 (2024/11/12) 9 | 10 | * Firefox Developer Edition 133.0b7 11 | * Portapps 3.15.0 12 | 13 | ## 126.0b9-50 (2024/05/05) 14 | 15 | * Firefox Developer Edition 126.0b9 16 | * Portapps 3.10.0 17 | 18 | ## 122.0b3-49 (2023/12/25) 19 | 20 | * Firefox Developer Edition 122.0b3 21 | * Portapps 3.9.0 22 | 23 | ## 115.0b9-48 (2023/07/03) 24 | 25 | * Firefox Developer Edition 115.0b9 26 | * Portapps 3.8.0 27 | 28 | ## 110.0b9-47 (2023/02/12) 29 | 30 | * Firefox Developer Edition 110.0b9 31 | * Portapps 3.7.0 32 | 33 | ## 106.0b7-46 (2022/10/04) 34 | 35 | * Firefox Developer Edition 106.0b7 36 | * Portapps 3.6.0 37 | * Bump github.com/kevinburke/go-bindata 38 | 39 | ## 101.0b9-45 (2022/05/22) 40 | 41 | * Firefox Developer Edition 101.0b9 42 | * Portapps 3.5.0 43 | * Bump github.com/kevinburke/go-bindata (#47) 44 | * Bump github.com/pierrec/lz4/v3 from 3.3.4 to 3.3.5 (#53) 45 | 46 | ## 97.0b8-44 (2022/01/27) 47 | 48 | * Firefox Developer Edition 97.0b8 49 | * Portapps 3.4.0 50 | 51 | ## 93.0b6-43 (2021/07/25) 52 | 53 | * Firefox Developer Edition 93.0b6 54 | * Portapps 3.3.1 55 | 56 | ## 91.0b6-42 (2021/07/25) 57 | 58 | * Firefox Developer Edition 91.0b6 59 | 60 | ## 89.0b15-41 (2021/05/22) 61 | 62 | * Firefox Developer Edition 89.0b15 63 | 64 | ## 88.0b5-40 (2021/04/04) 65 | 66 | * Firefox Developer Edition 88.0b5 67 | * Portapps 3.3.0 68 | * No more win32 release 69 | 70 | ## 86.0b5-39 (2021/02/06) 71 | 72 | * Firefox Developer Edition 86.0b5 73 | * Portapps 3.1.0 74 | 75 | ## 84.0b8-38 (2020/12/07) 76 | 77 | * Firefox Developer Edition 84.0b8 78 | * Portapps 3.0.3 79 | 80 | ## 83.0b5-37 (2020/10/28) 81 | 82 | * Firefox Developer Edition 83.0b5 83 | 84 | ## 82.0b2-36 (2020/09/29) 85 | 86 | * Firefox Developer Edition 82.0b2 87 | 88 | ## 81.0b1-35 (2020/08/24) 89 | 90 | * Firefox Developer Edition 81.0b1 91 | * Portapps 2.6.0 92 | 93 | ## 80.0b2-34 (2020/07/31) 94 | 95 | * Firefox Developer Edition 80.0b2 96 | 97 | ## 79.0b5-33 (2020/07/08) 98 | 99 | * Firefox Developer Edition 79.0b5 100 | 101 | ## 78.0b6-32 (2020/06/13) 102 | 103 | * Firefox Developer Edition 78.0b6 104 | 105 | ## 77.0b3-31 (2020/05/29) 106 | 107 | * Fix addons startup (portapps/phyrox-portable#3) 108 | * Portapps 2.4.4 109 | 110 | ## 77.0b3-30 (2020/05/10) 111 | 112 | * Firefox Developer Edition 77.0b3 113 | * Allow custom `policies.json` 114 | * `DisableTelemetry` and `DisableFirefoxStudies` removed (use policies file instead) 115 | * Portapps 2.2.4 116 | 117 | ## 76.0b6-29 (2020/04/21) 118 | 119 | * Firefox Developer Edition 76.0b6 120 | * Portapps 2.1.2 121 | 122 | ## 75.0b7-28 (2020/03/25) 123 | 124 | * Firefox Developer Edition 75.0b7 125 | * Add `cleanup` config 126 | * Portapps 1.31.0 127 | 128 | ## 74.0b3-27 (2020/02/14) 129 | 130 | * Firefox Developer Edition 74.0b3 131 | 132 | ## 72.0b2-26 (2019/12/03) 133 | 134 | * Firefox Developer Edition 72.0b2 135 | 136 | ## 71.0b12-25 (2019/12/01) 137 | 138 | * Firefox Developer Edition 71.0b12 139 | 140 | ## 71.0b5-24 (2019/12/01) 141 | 142 | * Following a trademark violation report (#5), name and logo have been changed 143 | * Portapps 1.30.1 144 | 145 | ## 71.0b5-23 (2019/10/29) 146 | 147 | * Firefox Developer Edition 71.0b5 148 | * Update Firefox logo 149 | 150 | ## 71.0b1-22 (2019/10/16) 151 | 152 | * Firefox Developer Edition 71.0b1 153 | 154 | ## 70.0b12-21 (2019/10/08) 155 | 156 | * Firefox Developer Edition 70.0b12 157 | * Portapps 1.28.0 158 | 159 | ## 70.0b6-20 (2019/09/13) 160 | 161 | * Firefox Developer Edition 70.0b6 162 | * Fix addons disabled on startup (#1) 163 | * Portapps 1.26.1 164 | 165 | ## 70.0b2-19 (2019/09/02) 166 | 167 | * Firefox Developer Edition 70.0b2 168 | 169 | ## 69.0b16-18 (2019/09/02) 170 | 171 | * Firefox Developer Edition 69.0b16 172 | * Portapps 1.26.0 173 | 174 | ## 69.0b11-17 (2019/08/07) 175 | 176 | * Firefox Developer Edition 69.0b11 177 | * Portapps 1.25.0 178 | 179 | ## 69.0b4-16 (2019/07/12) 180 | 181 | * Firefox Developer Edition 69.0b4 182 | 183 | ## 69.0b1-15 (2019/07/02) 184 | 185 | * Firefox Developer Edition 69.0b1 186 | 187 | ## 68.0b13-14 (2019/06/26) 188 | 189 | * Firefox Developer Edition 68.0b13 190 | 191 | ## 68.0b10-13 (2019/06/16) 192 | 193 | * Firefox Developer Edition 68.0b10 194 | 195 | ## 68.0b7-12 (2019/06/06) 196 | 197 | * Firefox Developer Edition 68.0b7 198 | * Extensions break on path change (portapps/firefox-portable#2) 199 | 200 | ## 68.0b6-11 (2019/06/02) 201 | 202 | * Firefox Developer Edition 68.0b6 203 | 204 | ## 68.0b2-10 (2019/05/20) 205 | 206 | * Firefox Developer Edition 68.0b2 207 | * Portapps 1.24.1 208 | 209 | ## 67.0b18-9 (2019/05/08) 210 | 211 | * Firefox Developer Edition 67.0b18 212 | * Portapps 1.23.0 213 | 214 | ## 67.0b17-8 (2019/05/06) 215 | 216 | * Firefox Developer Edition 67.0b17 217 | * Portapps 1.22.2 218 | 219 | ## 67.0b10-7 (2019/04/14) 220 | 221 | * Firefox Developer Edition 67.0b10 222 | 223 | ## 67.0b6-6 (2019/03/31) 224 | 225 | * Firefox Developer Edition 67.0b6 226 | * Portapps 1.21.0 227 | 228 | ## 67.0b4-5 (2019/03/23) 229 | 230 | * Firefox Developer Edition 67.0b4 231 | 232 | ## 67.0b3-4 (2019/03/20) 233 | 234 | * Firefox Developer Edition 67.0b3 235 | 236 | ## 66.0b14-3 (2019/03/17) 237 | 238 | * Firefox Developer Edition 66.0b14 239 | * Handle notifications 240 | * Portapps 1.20.3 241 | 242 | ## 66.0b13-2 (2019/03/06) 243 | 244 | * Initial version based on Firefox Developer Edition 66.0b13 245 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2025 CrazyMax 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | GitHub release 5 | Total downloads 6 | Build Status 7 | Go Report 8 |
Become a sponsor 9 | Donate Paypal 10 |

11 | 12 | ## About 13 | 14 | Phyrox Developer Edition (based on Mozilla Firefox Developer Edition) portable app made with 🚀 [Portapps](https://portapps.io).
15 | Documentation and downloads can be found on https://portapps.io/app/phyrox-developer-portable/ 16 | 17 | > :warning: Following a trademark violation report ([#5](https://github.com/portapps/phyrox-developer-portable/issues/5)) from Mozilla, Firefox Developer Edition portable has been named Phyrox Developer Edition portable on Portapps. Nothing changes except its name. 18 | 19 | ## Contributing 20 | 21 | Want to contribute? Awesome! The most basic way to show your support is to star the project, or to raise issues. If 22 | you want to open a pull request, please read the [contributing guidelines](https://portapps.io/doc/contribute/). 23 | 24 | You can also support this project by [**becoming a sponsor on GitHub**](https://github.com/sponsors/crazy-max) or by 25 | making a [Paypal donation](https://www.paypal.me/crazyws) to ensure this journey continues indefinitely! 26 | 27 | Thanks again for your support, it is much appreciated! :pray: 28 | 29 | ## License 30 | 31 | MIT. See `LICENSE` for more details.
32 | Logo credit to [Nadja Hallfahrt](http://blog.artcore-illustrations.de/).
33 | Rocket icon credit to [Squid Ink](http://thesquid.ink). 34 | -------------------------------------------------------------------------------- /assets/assets.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-bindata. DO NOT EDIT. 2 | // sources: 3 | // res/FirefoxDeveloperEdition.lnk (1.294kB) 4 | 5 | package assets 6 | 7 | import ( 8 | "bytes" 9 | "compress/gzip" 10 | "crypto/sha256" 11 | "fmt" 12 | "io" 13 | "os" 14 | "path/filepath" 15 | "strings" 16 | "time" 17 | ) 18 | 19 | func bindataRead(data []byte, name string) ([]byte, error) { 20 | gz, err := gzip.NewReader(bytes.NewBuffer(data)) 21 | if err != nil { 22 | return nil, fmt.Errorf("read %q: %w", name, err) 23 | } 24 | 25 | var buf bytes.Buffer 26 | _, err = io.Copy(&buf, gz) 27 | clErr := gz.Close() 28 | 29 | if err != nil { 30 | return nil, fmt.Errorf("read %q: %w", name, err) 31 | } 32 | if clErr != nil { 33 | return nil, err 34 | } 35 | 36 | return buf.Bytes(), nil 37 | } 38 | 39 | type asset struct { 40 | bytes []byte 41 | info os.FileInfo 42 | digest [sha256.Size]byte 43 | } 44 | 45 | type bindataFileInfo struct { 46 | name string 47 | size int64 48 | mode os.FileMode 49 | modTime time.Time 50 | } 51 | 52 | func (fi bindataFileInfo) Name() string { 53 | return fi.name 54 | } 55 | func (fi bindataFileInfo) Size() int64 { 56 | return fi.size 57 | } 58 | func (fi bindataFileInfo) Mode() os.FileMode { 59 | return fi.mode 60 | } 61 | func (fi bindataFileInfo) ModTime() time.Time { 62 | return fi.modTime 63 | } 64 | func (fi bindataFileInfo) IsDir() bool { 65 | return false 66 | } 67 | func (fi bindataFileInfo) Sys() interface{} { 68 | return nil 69 | } 70 | 71 | var _firefoxdevelopereditionLnk = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x93\x5f\x68\x23\x55\x14\xc6\x7f\x71\xbb\xae\x75\x5f\x1a\x5c\xc4\x2d\x5d\x3a\x0f\x22\x5d\x35\xd9\x49\x9a\xa4\x49\xd6\x95\xa6\x49\xc6\x68\xe2\x36\xb4\x2a\x45\xe6\xc1\xd6\xdc\xb4\xa3\x49\x27\x9d\xd4\x92\x42\x29\x0a\x42\xb1\xa8\x88\x0a\x56\x44\x1a\x8b\xd2\x0a\xb5\xe0\x1f\x10\x69\x91\x82\xf8\xe2\x83\x04\x69\x41\x14\x6a\x2b\xfa\xa0\x20\xc5\xfa\xa4\x16\x2a\x77\x32\x91\xa6\x2a\x8a\xb0\xe7\xe1\x9c\xe4\x9c\x73\xe7\xfb\xee\x77\xcf\xc9\x00\xae\x73\xd7\x21\x6d\xd3\xf6\x68\xaf\x01\x0a\xb0\xb7\xf4\x61\xe1\xee\xed\x2d\xd7\x77\x3f\xd7\xe3\x95\xa3\x4c\xf1\xe5\x2f\xb6\x5c\xb5\x0b\x67\xec\x46\x17\xcd\xf6\x96\xeb\x1c\x9d\xd9\xdd\xfe\x9a\xf2\x63\xd4\x68\x5b\xfa\xf2\x06\xee\x50\xd5\xd7\xcf\x73\x29\x1e\xd5\xf9\xab\x2d\xe0\xb3\xe3\xe8\xd5\xc7\x36\xdc\x64\x07\xfa\xef\x19\x88\xcd\xfa\xe1\x49\x5a\x69\x61\xff\xe3\x4b\xf7\x47\xef\x92\x35\x2f\xd0\x79\x7d\x33\xe0\x43\xb6\x4f\xbf\xd1\x4a\x16\x0b\x93\x51\x2c\x86\x29\xa2\xa0\x61\x50\x40\x50\x46\xa1\x8b\x0a\x61\x42\x5c\x04\x7a\x29\x33\x86\xa0\x40\x81\x6e\xfc\x78\xc9\xd9\xbf\xef\xc4\x83\x1f\x1f\x61\x7c\xf4\x00\xb7\x30\x73\x8c\x57\x1b\xda\xbd\x03\x49\xad\x7f\xd6\x07\x39\x87\x97\xcc\x37\x78\xb9\xdf\x97\x9c\xce\x9e\xb8\xd9\xf2\xe5\xac\xcd\xc3\x42\x90\xc7\xa4\x82\x42\x02\xc1\x94\x8d\x6f\x52\x42\x60\xa1\x90\x24\x87\xc1\x24\x06\x26\xe3\x36\xf6\x08\x7e\xa4\xbc\xb9\xab\xab\x13\x0a\x79\xc3\x12\x79\xb3\xe2\x15\x15\x41\xea\x6f\xd0\x6b\x1f\x48\xf4\xd6\x13\xe8\x9f\xb4\x3f\x4d\xbe\x09\xdd\x8b\xa0\x82\x00\xda\x81\x32\xd0\xe1\xa8\x29\x63\xd0\x39\x67\x01\xe7\x81\x53\x40\x7c\xbd\x43\x6f\x03\x12\xc6\xad\x13\x4f\x08\x25\x4e\x3c\xaa\x67\x2d\x73\xd4\x1a\x2e\x2a\x9a\x51\x10\x65\xa5\xab\x12\x0e\x5d\xd4\xb5\x3a\x43\x25\x21\xa6\x44\xc1\x2c\x09\x4b\x49\xe6\x8c\x49\xc3\x1c\xd7\x8f\x73\xa7\x0f\x2f\x5e\xf4\x26\xff\xdf\x1e\x4e\xff\x1f\x42\xea\xff\x70\x7d\x95\x38\xd1\x6b\x8a\x2c\x25\x3b\x0d\xd5\xdb\x81\x4f\x1d\x79\xcf\x42\x75\xbf\xf7\xe1\x99\xdf\xab\x87\xe9\xb9\xfb\x36\x0f\x76\x3f\xfa\xed\x79\x59\x7b\xa4\x2e\x75\x75\xc8\x91\xbf\xf4\xa8\x67\x6c\x38\x27\xca\x8d\x67\xcc\xad\xad\x4d\x4e\x1f\xac\x26\x5f\x7c\xea\xfb\xb7\xbf\x5a\x99\x6b\xf1\xbf\x70\x79\xa7\x23\xf6\x83\xfb\xd5\xc7\x1f\x78\xef\xd4\x8d\xf3\x99\x7f\xab\xab\x2e\x7b\x34\xaa\xcf\x00\xbe\xc1\xec\xe0\xb7\xf3\x43\xda\x46\x26\x1c\x5f\x3f\xbc\xe9\xa5\xdb\x16\x8a\x9f\x17\x81\x16\x09\xd4\x09\xc8\x69\x1a\xc4\x83\x0f\x0f\x41\x67\x23\x3c\x74\xd3\x43\x84\x00\x01\x22\x44\x08\xd9\xc2\xc8\x5a\x84\x20\x2a\x01\xfb\xbf\x9f\xb0\xdd\x19\x24\x80\x8a\x6a\x6f\x91\x3c\x11\xb2\xbf\x56\xcf\xd4\x6d\xc4\x21\xf2\x60\x57\x66\x71\x7a\x31\x92\x5e\xa9\xed\x6d\x79\xf6\xb6\x7f\x71\x37\x36\x48\xba\xa3\xa3\xfa\x40\x9e\x6e\x30\x93\x55\x0d\x8d\x04\x01\x92\x24\xe8\x23\x44\x1f\x31\x62\xf4\xd8\xb9\x38\xdd\x7f\x4e\x7e\xc4\x41\x78\xf7\xe6\x62\xe2\x9d\xe7\x4a\xa9\xe5\x54\xaf\xf7\xcd\x2b\x95\x67\x2f\x00\x63\xb2\x21\x05\x7c\xb3\xd3\xfe\xd3\xdc\xaf\xfb\xa9\x57\xd6\xbe\x4e\x9f\xf9\x6c\x56\x3d\xbe\x3a\x7f\x04\x00\x00\xff\xff\xb2\xca\x3f\x21\x0e\x05\x00\x00") 72 | 73 | func firefoxdevelopereditionLnkBytes() ([]byte, error) { 74 | return bindataRead( 75 | _firefoxdevelopereditionLnk, 76 | "FirefoxDeveloperEdition.lnk", 77 | ) 78 | } 79 | 80 | func firefoxdevelopereditionLnk() (*asset, error) { 81 | bytes, err := firefoxdevelopereditionLnkBytes() 82 | if err != nil { 83 | return nil, err 84 | } 85 | 86 | info := bindataFileInfo{name: "FirefoxDeveloperEdition.lnk", size: 1294, mode: os.FileMode(0666), modTime: time.Unix(1572378781, 0)} 87 | a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf1, 0x64, 0x23, 0x53, 0x23, 0x7a, 0x80, 0x9d, 0xb4, 0x38, 0x88, 0x8e, 0x8e, 0xb2, 0xd2, 0xad, 0x74, 0x67, 0xbc, 0x64, 0x79, 0x2b, 0x22, 0x77, 0x32, 0xe2, 0xef, 0x5f, 0x13, 0x74, 0xac, 0x70}} 88 | return a, nil 89 | } 90 | 91 | // Asset loads and returns the asset for the given name. 92 | // It returns an error if the asset could not be found or 93 | // could not be loaded. 94 | func Asset(name string) ([]byte, error) { 95 | canonicalName := strings.Replace(name, "\\", "/", -1) 96 | if f, ok := _bindata[canonicalName]; ok { 97 | a, err := f() 98 | if err != nil { 99 | return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) 100 | } 101 | return a.bytes, nil 102 | } 103 | return nil, fmt.Errorf("Asset %s not found", name) 104 | } 105 | 106 | // AssetString returns the asset contents as a string (instead of a []byte). 107 | func AssetString(name string) (string, error) { 108 | data, err := Asset(name) 109 | return string(data), err 110 | } 111 | 112 | // MustAsset is like Asset but panics when Asset would return an error. 113 | // It simplifies safe initialization of global variables. 114 | func MustAsset(name string) []byte { 115 | a, err := Asset(name) 116 | if err != nil { 117 | panic("asset: Asset(" + name + "): " + err.Error()) 118 | } 119 | 120 | return a 121 | } 122 | 123 | // MustAssetString is like AssetString but panics when Asset would return an 124 | // error. It simplifies safe initialization of global variables. 125 | func MustAssetString(name string) string { 126 | return string(MustAsset(name)) 127 | } 128 | 129 | // AssetInfo loads and returns the asset info for the given name. 130 | // It returns an error if the asset could not be found or 131 | // could not be loaded. 132 | func AssetInfo(name string) (os.FileInfo, error) { 133 | canonicalName := strings.Replace(name, "\\", "/", -1) 134 | if f, ok := _bindata[canonicalName]; ok { 135 | a, err := f() 136 | if err != nil { 137 | return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) 138 | } 139 | return a.info, nil 140 | } 141 | return nil, fmt.Errorf("AssetInfo %s not found", name) 142 | } 143 | 144 | // AssetDigest returns the digest of the file with the given name. It returns an 145 | // error if the asset could not be found or the digest could not be loaded. 146 | func AssetDigest(name string) ([sha256.Size]byte, error) { 147 | canonicalName := strings.Replace(name, "\\", "/", -1) 148 | if f, ok := _bindata[canonicalName]; ok { 149 | a, err := f() 150 | if err != nil { 151 | return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s can't read by error: %v", name, err) 152 | } 153 | return a.digest, nil 154 | } 155 | return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s not found", name) 156 | } 157 | 158 | // Digests returns a map of all known files and their checksums. 159 | func Digests() (map[string][sha256.Size]byte, error) { 160 | mp := make(map[string][sha256.Size]byte, len(_bindata)) 161 | for name := range _bindata { 162 | a, err := _bindata[name]() 163 | if err != nil { 164 | return nil, err 165 | } 166 | mp[name] = a.digest 167 | } 168 | return mp, nil 169 | } 170 | 171 | // AssetNames returns the names of the assets. 172 | func AssetNames() []string { 173 | names := make([]string, 0, len(_bindata)) 174 | for name := range _bindata { 175 | names = append(names, name) 176 | } 177 | return names 178 | } 179 | 180 | // _bindata is a table, holding each asset generator, mapped to its name. 181 | var _bindata = map[string]func() (*asset, error){ 182 | "FirefoxDeveloperEdition.lnk": firefoxdevelopereditionLnk, 183 | } 184 | 185 | // AssetDebug is true if the assets were built with the debug flag enabled. 186 | const AssetDebug = false 187 | 188 | // AssetDir returns the file names below a certain 189 | // directory embedded in the file by go-bindata. 190 | // For example if you run go-bindata on data/... and data contains the 191 | // following hierarchy: 192 | // 193 | // data/ 194 | // foo.txt 195 | // img/ 196 | // a.png 197 | // b.png 198 | // 199 | // then AssetDir("data") would return []string{"foo.txt", "img"}, 200 | // AssetDir("data/img") would return []string{"a.png", "b.png"}, 201 | // AssetDir("foo.txt") and AssetDir("notexist") would return an error, and 202 | // AssetDir("") will return []string{"data"}. 203 | func AssetDir(name string) ([]string, error) { 204 | node := _bintree 205 | if len(name) != 0 { 206 | canonicalName := strings.Replace(name, "\\", "/", -1) 207 | pathList := strings.Split(canonicalName, "/") 208 | for _, p := range pathList { 209 | node = node.Children[p] 210 | if node == nil { 211 | return nil, fmt.Errorf("Asset %s not found", name) 212 | } 213 | } 214 | } 215 | if node.Func != nil { 216 | return nil, fmt.Errorf("Asset %s not found", name) 217 | } 218 | rv := make([]string, 0, len(node.Children)) 219 | for childName := range node.Children { 220 | rv = append(rv, childName) 221 | } 222 | return rv, nil 223 | } 224 | 225 | type bintree struct { 226 | Func func() (*asset, error) 227 | Children map[string]*bintree 228 | } 229 | 230 | var _bintree = &bintree{nil, map[string]*bintree{ 231 | "FirefoxDeveloperEdition.lnk": {firefoxdevelopereditionLnk, map[string]*bintree{}}, 232 | }} 233 | 234 | // RestoreAsset restores an asset under the given directory. 235 | func RestoreAsset(dir, name string) error { 236 | data, err := Asset(name) 237 | if err != nil { 238 | return err 239 | } 240 | info, err := AssetInfo(name) 241 | if err != nil { 242 | return err 243 | } 244 | err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) 245 | if err != nil { 246 | return err 247 | } 248 | err = os.WriteFile(_filePath(dir, name), data, info.Mode()) 249 | if err != nil { 250 | return err 251 | } 252 | return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) 253 | } 254 | 255 | // RestoreAssets restores an asset under the given directory recursively. 256 | func RestoreAssets(dir, name string) error { 257 | children, err := AssetDir(name) 258 | // File 259 | if err != nil { 260 | return RestoreAsset(dir, name) 261 | } 262 | // Dir 263 | for _, child := range children { 264 | err = RestoreAssets(dir, filepath.Join(name, child)) 265 | if err != nil { 266 | return err 267 | } 268 | } 269 | return nil 270 | } 271 | 272 | func _filePath(dir, name string) string { 273 | canonicalName := strings.Replace(name, "\\", "/", -1) 274 | return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...) 275 | } 276 | -------------------------------------------------------------------------------- /build.properties: -------------------------------------------------------------------------------- 1 | # Portapps 2 | core.dir = ../portapps 3 | 4 | # App 5 | app = phyrox-developer 6 | app.name = Phyrox Developer Edition 7 | app.type = archive 8 | app.version = 138.0b3 9 | app.release = 52 10 | app.homepage = https://www.mozilla.org/en-US/firefox 11 | 12 | # Portable app 13 | papp.id = ${app}-portable 14 | papp.guid = {829F3ADB-1DE7-4176-8DA8-532558319F16} 15 | papp.name = ${app.name} Portable 16 | papp.desc = ${app.name} portable on Windows by Portapps 17 | papp.url = https://github.com/portapps/${papp.id} 18 | papp.folder = app 19 | 20 | # Official artifacts 21 | atf.id = Firefox 22 | atf.win64.filename = ${atf.id}DevEditionSetup-${app.version}-win64 23 | atf.win64.ext = .exe 24 | atf.win64.url = https://ftp.mozilla.org/pub/devedition/releases/${app.version}/win64/en-US/Firefox%20Setup%20${app.version}.exe 25 | atf.win64.assertextract = core/firefox.exe 26 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/portapps/phyrox-developer-portable 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | github.com/Jeffail/gabs v1.4.0 7 | github.com/kevinburke/go-bindata/v4 v4.0.2 8 | github.com/pierrec/lz4/v3 v3.3.5 9 | github.com/pkg/errors v0.9.1 10 | github.com/portapps/portapps/v3 v3.16.0 11 | ) 12 | 13 | require ( 14 | github.com/akavel/rsrc v0.10.2 // indirect 15 | github.com/go-ole/go-ole v1.3.0 // indirect 16 | github.com/go-viper/mapstructure/v2 v2.2.1 // indirect 17 | github.com/ilya1st/rotatewriter v0.0.0-20171126183947-3df0c1a3ed6d // indirect 18 | github.com/josephspurrier/goversioninfo v1.5.0 // indirect 19 | github.com/mattn/go-colorable v0.1.13 // indirect 20 | github.com/mattn/go-isatty v0.0.19 // indirect 21 | github.com/rs/zerolog v1.34.0 // indirect 22 | golang.org/x/sys v0.32.0 // indirect 23 | gopkg.in/yaml.v3 v3.0.1 // indirect 24 | ) 25 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | code.cloudfoundry.org/bytefmt v0.0.0-20190710193110-1eb035ffe2b6/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc= 2 | github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= 3 | github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= 4 | github.com/akavel/rsrc v0.10.2 h1:Zxm8V5eI1hW4gGaYsJQUhxpjkENuG91ki8B4zCrvEsw= 5 | github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= 6 | github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 7 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 9 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/frankban/quicktest v1.4.0 h1:rCSCih1FnSWJEel/eub9wclBSqpF2F/PuvxUWGWnbO8= 11 | github.com/frankban/quicktest v1.4.0/go.mod h1:36zfPVQyHxymz4cH7wlDmVwDrJuljRB60qkgn7rorfQ= 12 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 13 | github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= 14 | github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= 15 | github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= 16 | github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 17 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 18 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 19 | github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= 20 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 21 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 22 | github.com/ilya1st/rotatewriter v0.0.0-20171126183947-3df0c1a3ed6d h1:OGuVAVny/97zsQ5BWg0mOjzTBBD9zR+Lug1co144+rU= 23 | github.com/ilya1st/rotatewriter v0.0.0-20171126183947-3df0c1a3ed6d/go.mod h1:S1q6q+21PRGd0WRX+fHjQ+TOe3CgpSv7zgCWnZcbxCs= 24 | github.com/josephspurrier/goversioninfo v1.5.0 h1:9TJtORoyf4YMoWSOo/cXFN9A/lB3PniJ91OxIH6e7Zg= 25 | github.com/josephspurrier/goversioninfo v1.5.0/go.mod h1:6MoTvFZ6GKJkzcdLnU5T/RGYUbHQbKpYeNP0AgQLd2o= 26 | github.com/kevinburke/go-bindata/v4 v4.0.2 h1:6qQI0nNTL27wM1En8zQHGBEPp3ETzgFU6hVdSjlkrfE= 27 | github.com/kevinburke/go-bindata/v4 v4.0.2/go.mod h1:M/CkBqw2qCZ1Ztv5JyKgocGYWyUkYlDqkqXS1ktLe5c= 28 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 29 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 30 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 31 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 32 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 33 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 34 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 35 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 36 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= 37 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 38 | github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= 39 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 40 | github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 41 | github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 42 | github.com/pierrec/cmdflag v0.0.2/go.mod h1:a3zKGZ3cdQUfxjd0RGMLZr8xI3nvpJOB+m6o/1X5BmU= 43 | github.com/pierrec/lz4/v3 v3.3.5 h1:JzKda6jLXZpQK5/ulrEfT1I66tsKiGlw6sjKssFpwt8= 44 | github.com/pierrec/lz4/v3 v3.3.5/go.mod h1:280XNCGS8jAcG++AHdd6SeWnzyJ1w9oow2vbORyey8Q= 45 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 46 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 47 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 48 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 49 | github.com/portapps/portapps/v3 v3.16.0 h1:wQyDDoYAh7YTTaIwo48K8lbegODZuasSq4S7XIppe6s= 50 | github.com/portapps/portapps/v3 v3.16.0/go.mod h1:4ue65AQ4rAe0iiOr3tTvmmNyDYIB9R6JywBBEPrJKZU= 51 | github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= 52 | github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= 53 | github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= 54 | github.com/schollz/progressbar/v2 v2.13.2/go.mod h1:6YZjqdthH6SCZKv2rqGryrxPtfmRB/DWZxSMfCXPyD8= 55 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 56 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 57 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 58 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 59 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 60 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 61 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 62 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 63 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 64 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 65 | golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 66 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 67 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 68 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 69 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 70 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 71 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 72 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 73 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 74 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 75 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 76 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | //go:generate go install -v github.com/kevinburke/go-bindata/v4/go-bindata 2 | //go:generate go-bindata -prefix res/ -pkg assets -o assets/assets.go res/FirefoxDeveloperEdition.lnk 3 | //go:generate go install -v github.com/josephspurrier/goversioninfo/cmd/goversioninfo 4 | //go:generate goversioninfo -icon=res/papp.ico -manifest=res/papp.manifest 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "os" 10 | "path" 11 | "strings" 12 | 13 | "github.com/Jeffail/gabs" 14 | "github.com/pkg/errors" 15 | "github.com/portapps/phyrox-developer-portable/assets" 16 | "github.com/portapps/portapps/v3" 17 | "github.com/portapps/portapps/v3/pkg/log" 18 | "github.com/portapps/portapps/v3/pkg/mutex" 19 | "github.com/portapps/portapps/v3/pkg/shortcut" 20 | "github.com/portapps/portapps/v3/pkg/utl" 21 | "github.com/portapps/portapps/v3/pkg/win" 22 | ) 23 | 24 | type config struct { 25 | Profile string `yaml:"profile" mapstructure:"profile"` 26 | MultipleInstances bool `yaml:"multiple_instances" mapstructure:"multiple_instances"` 27 | Cleanup bool `yaml:"cleanup" mapstructure:"cleanup"` 28 | } 29 | 30 | var ( 31 | app *portapps.App 32 | cfg *config 33 | ) 34 | 35 | func init() { 36 | var err error 37 | 38 | // Default config 39 | cfg = &config{ 40 | Profile: "default", 41 | MultipleInstances: false, 42 | Cleanup: false, 43 | } 44 | 45 | // Init app 46 | if app, err = portapps.NewWithCfg("phyrox-developer-portable", "Phyrox Developer Edition", cfg); err != nil { 47 | log.Fatal().Err(err).Msg("Cannot initialize application. See log file for more info.") 48 | } 49 | } 50 | 51 | func main() { 52 | utl.CreateFolder(app.DataPath) 53 | profileFolder := utl.CreateFolder(app.DataPath, "profile", cfg.Profile) 54 | 55 | app.Process = utl.PathJoin(app.AppPath, "firefox.exe") 56 | app.Args = []string{ 57 | "--profile", 58 | profileFolder, 59 | } 60 | 61 | // Set env vars 62 | crashreporterFolder := utl.CreateFolder(app.DataPath, "crashreporter") 63 | pluginsFolder := utl.CreateFolder(app.DataPath, "plugins") 64 | os.Setenv("MOZ_CRASHREPORTER", "0") 65 | os.Setenv("MOZ_CRASHREPORTER_DATA_DIRECTORY", crashreporterFolder) 66 | os.Setenv("MOZ_CRASHREPORTER_DISABLE", "1") 67 | os.Setenv("MOZ_CRASHREPORTER_NO_REPORT", "1") 68 | os.Setenv("MOZ_DATA_REPORTING", "0") 69 | os.Setenv("MOZ_MAINTENANCE_SERVICE", "0") 70 | os.Setenv("MOZ_PLUGIN_PATH", pluginsFolder) 71 | os.Setenv("MOZ_UPDATER", "0") 72 | 73 | // Create and check mutex 74 | mu, err := mutex.Create(app.ID) 75 | defer mutex.Release(mu) 76 | if err != nil { 77 | if !cfg.MultipleInstances { 78 | log.Error().Msg("You have to enable multiple instances in your configuration if you want to launch another instance") 79 | if _, err = win.MsgBox( 80 | fmt.Sprintf("%s portable", app.Name), 81 | "Other instance detected. You have to enable multiple instances in your configuration if you want to launch another instance.", 82 | win.MsgBoxBtnOk|win.MsgBoxIconError); err != nil { 83 | log.Error().Err(err).Msg("Cannot create dialog box") 84 | } 85 | return 86 | } else { 87 | log.Warn().Msg("Another instance is already running") 88 | } 89 | } 90 | 91 | // Cleanup on exit 92 | if cfg.Cleanup { 93 | defer func() { 94 | utl.Cleanup([]string{ 95 | path.Join(os.Getenv("APPDATA"), "Mozilla", "Firefox"), 96 | path.Join(os.Getenv("LOCALAPPDATA"), "Mozilla", "Firefox"), 97 | path.Join(os.Getenv("USERPROFILE"), "AppData", "LocalLow", "Mozilla"), 98 | }) 99 | }() 100 | } 101 | 102 | // Multiple instances 103 | if cfg.MultipleInstances { 104 | log.Info().Msg("Multiple instances enabled") 105 | app.Args = append(app.Args, "--no-remote") 106 | } 107 | 108 | // Policies 109 | if err := createPolicies(); err != nil { 110 | log.Fatal().Err(err).Msg("Cannot create policies") 111 | } 112 | 113 | // Fix extensions path 114 | if err := updateAddonStartup(profileFolder); err != nil { 115 | log.Error().Err(err).Msg("Cannot fix extensions path") 116 | } 117 | 118 | // Copy default shortcut 119 | shortcutPath := path.Join(os.Getenv("APPDATA"), "Microsoft", "Windows", "Start Menu", "Programs", "Phyrox Developer Edition Portable.lnk") 120 | defaultShortcut, err := assets.Asset("FirefoxDeveloperEdition.lnk") 121 | if err != nil { 122 | log.Error().Err(err).Msg("Cannot load asset FirefoxDeveloperEdition.lnk") 123 | } 124 | err = os.WriteFile(shortcutPath, defaultShortcut, 0644) 125 | if err != nil { 126 | log.Error().Err(err).Msg("Cannot write default shortcut") 127 | } 128 | 129 | // Update default shortcut 130 | err = shortcut.Create(shortcut.Shortcut{ 131 | ShortcutPath: shortcutPath, 132 | TargetPath: app.Process, 133 | Arguments: shortcut.Property{Clear: true}, 134 | Description: shortcut.Property{Value: "Phyrox Developer Edition Portable by Portapps"}, 135 | IconLocation: shortcut.Property{Value: app.Process}, 136 | WorkingDirectory: shortcut.Property{Value: app.AppPath}, 137 | }) 138 | if err != nil { 139 | log.Error().Err(err).Msg("Cannot create shortcut") 140 | } 141 | defer func() { 142 | if err := os.Remove(shortcutPath); err != nil { 143 | log.Error().Err(err).Msg("Cannot remove shortcut") 144 | } 145 | }() 146 | 147 | defer app.Close() 148 | app.Launch(os.Args[1:]) 149 | } 150 | 151 | func createPolicies() error { 152 | appFile := utl.PathJoin(utl.CreateFolder(app.AppPath, "distribution"), "policies.json") 153 | dataFile := utl.PathJoin(app.DataPath, "policies.json") 154 | defaultPolicies := struct { 155 | Policies map[string]interface{} `json:"policies"` 156 | }{ 157 | Policies: map[string]interface{}{ 158 | "DisableAppUpdate": true, 159 | "DontCheckDefaultBrowser": true, 160 | }, 161 | } 162 | 163 | jsonPolicies, err := gabs.Consume(defaultPolicies) 164 | if err != nil { 165 | return errors.Wrap(err, "Cannot consume default policies") 166 | } 167 | log.Debug().Msgf("Default policies: %s", jsonPolicies.String()) 168 | 169 | if utl.Exists(dataFile) { 170 | rawCustomPolicies, err := os.ReadFile(dataFile) 171 | if err != nil { 172 | return errors.Wrap(err, "Cannot read custom policies") 173 | } 174 | 175 | jsonPolicies, err = gabs.ParseJSON(rawCustomPolicies) 176 | if err != nil { 177 | return errors.Wrap(err, "Cannot consume custom policies") 178 | } 179 | log.Debug().Msgf("Custom policies: %s", jsonPolicies.String()) 180 | 181 | jsonPolicies.Set(true, "policies", "DisableAppUpdate") 182 | jsonPolicies.Set(true, "policies", "DontCheckDefaultBrowser") 183 | } 184 | 185 | log.Debug().Msgf("Applied policies: %s", jsonPolicies.String()) 186 | err = os.WriteFile(appFile, []byte(jsonPolicies.StringIndent("", " ")), 0644) 187 | if err != nil { 188 | return errors.Wrap(err, "Cannot write policies") 189 | } 190 | 191 | return nil 192 | } 193 | 194 | func updateAddonStartup(profileFolder string) error { 195 | lz4File := path.Join(profileFolder, "addonStartup.json.lz4") 196 | if !utl.Exists(lz4File) || app.Prev.RootPath == "" { 197 | return nil 198 | } 199 | 200 | lz4Raw, err := mozLz4Decompress(lz4File) 201 | if err != nil { 202 | return err 203 | } 204 | 205 | prevPathLin := strings.Replace(utl.FormatUnixPath(app.Prev.RootPath), ` `, `%20`, -1) 206 | currPathLin := strings.Replace(utl.FormatUnixPath(app.RootPath), ` `, `%20`, -1) 207 | lz4Str := strings.Replace(string(lz4Raw), prevPathLin, currPathLin, -1) 208 | 209 | prevPathWin := strings.Replace(strings.Replace(utl.FormatWindowsPath(app.Prev.RootPath), `\`, `\\`, -1), ` `, `%20`, -1) 210 | currPathWin := strings.Replace(strings.Replace(utl.FormatWindowsPath(app.RootPath), `\`, `\\`, -1), ` `, `%20`, -1) 211 | lz4Str = strings.Replace(lz4Str, prevPathWin, currPathWin, -1) 212 | 213 | lz4Enc, err := mozLz4Compress([]byte(lz4Str)) 214 | if err != nil { 215 | return err 216 | } 217 | 218 | return os.WriteFile(lz4File, lz4Enc, 0644) 219 | } 220 | -------------------------------------------------------------------------------- /mozlz4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "io" 7 | "os" 8 | 9 | "github.com/pierrec/lz4/v3" 10 | "github.com/pkg/errors" 11 | ) 12 | 13 | const ( 14 | mozLz4Header = "mozLz40\x00" 15 | ) 16 | 17 | func mozLz4Decompress(filename string) ([]byte, error) { 18 | file, err := os.Open(filename) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | header := make([]byte, len(mozLz4Header)) 24 | _, err = file.Read(header) 25 | if err != nil { 26 | return nil, errors.Wrap(err, "couldn't read header") 27 | } 28 | if string(header) != mozLz4Header { 29 | return nil, errors.New("no mozLz4 header") 30 | } 31 | 32 | var size uint32 33 | err = binary.Read(file, binary.LittleEndian, &size) 34 | if err != nil { 35 | return nil, errors.Wrap(err, "couldn't read size") 36 | } 37 | 38 | src, err := io.ReadAll(file) 39 | if err != nil { 40 | return nil, errors.Wrap(err, "couldn't read compressed data") 41 | } 42 | 43 | out := make([]byte, size) 44 | _, err = lz4.UncompressBlock(src, out) 45 | if err != nil { 46 | return nil, errors.Wrap(err, "couldn't decompress data") 47 | } 48 | 49 | return out, nil 50 | } 51 | 52 | func mozLz4Compress(src []byte) ([]byte, error) { 53 | out := new(bytes.Buffer) 54 | 55 | _, err := out.Write([]byte(mozLz4Header)) 56 | if err != nil { 57 | return nil, errors.Wrap(err, "couldn't write header") 58 | } 59 | 60 | err = binary.Write(out, binary.LittleEndian, uint32(len(src))) 61 | if err != nil { 62 | return nil, errors.Wrap(err, "couldn't encode length") 63 | } 64 | 65 | buf := make([]byte, 10*len(src)) 66 | sz, err := lz4.CompressBlockHC(src, buf, -1) 67 | if err != nil { 68 | return nil, errors.Wrap(err, "couldn't compress data") 69 | } 70 | if sz == 0 { 71 | return nil, errors.New("data incompressible") 72 | } 73 | 74 | _, err = out.Write(buf[:sz]) 75 | if err != nil { 76 | return nil, errors.Wrap(err, "couldn't write compressed data") 77 | } 78 | 79 | return out.Bytes(), nil 80 | } 81 | -------------------------------------------------------------------------------- /res/FirefoxDeveloperEdition.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/portapps/phyrox-developer-portable/4a8eaf06fcedf033a7565ecd37fa022ca2726de0/res/FirefoxDeveloperEdition.lnk -------------------------------------------------------------------------------- /res/app.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/portapps/phyrox-developer-portable/4a8eaf06fcedf033a7565ecd37fa022ca2726de0/res/app.ico -------------------------------------------------------------------------------- /res/papp.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/portapps/phyrox-developer-portable/4a8eaf06fcedf033a7565ecd37fa022ca2726de0/res/papp.ico -------------------------------------------------------------------------------- /res/papp.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /res/papp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/portapps/phyrox-developer-portable/4a8eaf06fcedf033a7565ecd37fa022ca2726de0/res/papp.png -------------------------------------------------------------------------------- /res/run.iss: -------------------------------------------------------------------------------- 1 | [Run] 2 | Filename: {app}\{#pappId}.exe; Description: Run {#pappName}; Flags: nowait postinstall skipifsilent unchecked 3 | -------------------------------------------------------------------------------- /res/setup-mini.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/portapps/phyrox-developer-portable/4a8eaf06fcedf033a7565ecd37fa022ca2726de0/res/setup-mini.bmp -------------------------------------------------------------------------------- /tools/tools.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | // +build tools 3 | 4 | // Package tools tracks dependencies on binaries not referenced in this codebase. 5 | // https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module 6 | package tools 7 | 8 | import ( 9 | _ "github.com/kevinburke/go-bindata/v4" 10 | _ "github.com/portapps/portapps/v3/tools" 11 | ) 12 | --------------------------------------------------------------------------------