Skip to content

Commit

Permalink
Merge branch 'develop' into Issue-Badgerati#1329
Browse files Browse the repository at this point in the history
  • Loading branch information
Badgerati authored Jul 9, 2024
2 parents 04c22ab + 69790e7 commit 6e69777
Show file tree
Hide file tree
Showing 126 changed files with 6,539 additions and 2,013 deletions.
19 changes: 19 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "Codespace with PowerShell, Pester, Invoke-Build, and .NET 8",
"image": "mcr.microsoft.com/vscode/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/powershell:1": {},
"ghcr.io/devcontainers/features/dotnet:1": {
"version": "8.0"
}
},
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.powershell",
"pspester.pester-test"
]
}
},
"postCreateCommand": "pwsh -Command 'Install-Module -Name InvokeBuild,Pester -Force -SkipPublisherCheck; sleep 5; Invoke-Build Build '"
}
2 changes: 1 addition & 1 deletion .github/workflows/label-issue-project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
name: Add issue to project
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected].1
- uses: actions/[email protected].2
with:
project-url: https://github.com/users/Badgerati/projects/2
github-token: ${{ secrets.PROJECT_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/open-issue-project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
name: Add issue to project
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected].1
- uses: actions/[email protected].2
with:
project-url: https://github.com/users/Badgerati/projects/2
github-token: ${{ secrets.PROJECT_TOKEN }}
Expand Down
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,16 @@

Pode is a Cross-Platform framework for creating web servers to host [REST APIs](https://badgerati.github.io/Pode/Tutorials/Routes/Overview/), [Web Pages](https://badgerati.github.io/Pode/Tutorials/Routes/Examples/WebPages/), and [SMTP/TCP](https://badgerati.github.io/Pode/Servers/) Servers. Pode also allows you to render dynamic files using [`.pode`](https://badgerati.github.io/Pode/Tutorials/Views/Pode/) files, which are just embedded PowerShell, or other [Third-Party](https://badgerati.github.io/Pode/Tutorials/Views/ThirdParty/) template engines. Plus many more features, including [Azure Functions](https://badgerati.github.io/Pode/Hosting/AzureFunctions/) and [AWS Lambda](https://badgerati.github.io/Pode/Hosting/AwsLambda/) support!

<p align="center">
<img src="https://github.com/Badgerati/Pode/blob/develop/images/example_code_readme.svg?raw=true" width="70%" />
</p>
```powershell
Start-PodeServer -ScriptBlock {
Add-PodeEndPoint -Address localhost -port 32005 -Protocol Http
Add-PodeRoute -Method Get -Path '/ping' -ScriptBlock {
Write-PodeJsonResponse -Value @{value = 'pong' }
}
}
```

See [here](https://badgerati.github.io/Pode/Getting-Started/FirstApp) for building your first app! Don't know HTML, CSS, or JavaScript? No problem! [Pode.Web](https://github.com/Badgerati/Pode.Web) is currently a work in progress, and lets you build web pages using purely PowerShell!

Expand All @@ -49,8 +56,9 @@ Then navigate to `http://127.0.0.1:8000` in your browser.
* Cross-platform using PowerShell Core (with support for PS5)
* Docker support, including images for ARM/Raspberry Pi
* Azure Functions, AWS Lambda, and IIS support
* OpenAPI, Swagger, and ReDoc support
* Listen on a single or multiple IP address/hostnames
* OpenAPI specification version 3.0.x and 3.1.0
* OpenAPI documentation with Swagger, Redoc, RapidDoc, StopLight, OpenAPI-Explorer and RapiPdf
* Listen on a single or multiple IP(v4/v6) address/hostnames
* Cross-platform support for HTTP(S), WS(S), SSE, SMTP(S), and TCP(S)
* Host REST APIs, Web Pages, and Static Content (with caching)
* Support for custom error pages
Expand All @@ -73,6 +81,8 @@ Then navigate to `http://127.0.0.1:8000` in your browser.
* Support for File Watchers
* In-memory caching, with optional support for external providers (such as Redis)
* (Windows) Open the hosted server as a desktop application
* FileBrowsing support
* Localization (i18n) in Arabic, German, Spanish, France, Italian, Japanese, Korean, Polish, Portuguese, and Chinese

## 📦 Install

Expand Down
10 changes: 10 additions & 0 deletions docs/Getting-Started/FirstApp.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ Success, saved package.json
Import-Module -Name Pode -MaximumVersion 2.99.99
```

* To ensure that any errors during the import process are caught and handled appropriately, use a try-catch block:

```powershell
try {
Import-Module -Name 'Pode' -MaximumVersion 2.99.99 -ErrorAction Stop
} catch {
# exception management code
}
```

* Within your `server.ps1` file, first you need to start the Server. This is where the main script will go that defines how the server should function:

```powershell
Expand Down
55 changes: 55 additions & 0 deletions docs/Getting-Started/GitHubCodespace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@

# GitHub Codespace and Pode

GitHub Codespaces provides a cloud-based development environment directly integrated with GitHub. This allows you to set up your development environment with pre-configured settings, tools, and extensions. In this guide, we will walk you through using GitHub Codespace to work with Pode, a web framework for building web applications and APIs in PowerShell.

## Prerequisites

- A GitHub account
- A repository set up for your Pode project, including the `devcontainer.json` configuration file.

## Launching GitHub Codespace

1. **Open GitHub Codespace:**

Go to your GitHub repository on the web. Click on the green `Code` button, and then select `Open with Codespaces`. If you don't have any Codespaces created, you can create a new one by clicking `New codespace`.

2. **Codespace Initialization:**

Once the Codespace is created, it will use the existing `devcontainer.json` configuration to set up the environment. This includes installing the necessary VS Code extensions and PowerShell modules specified in the configuration.

3. **Verify the Setup:**

- The terminal in the Codespace will default to PowerShell (`pwsh`).
- Check that the required PowerShell modules are installed by running:

```powershell
Get-Module -ListAvailable
```
You should see `InvokeBuild` and `Pester` listed among the available modules.
## Running a Pode Application
1. **Use an Example Pode Project:**
Pode comes with several examples in the `examples` folder. You can run one of these examples to verify that your setup is working. For instance, let's use the `HelloWorld` example.
2. **Open HelloWorld**
Navigate to the `examples/HelloWorld` directory and open the `HelloWorld.ps1` file
3. **Run the sample**
Run the Pode server by executing the `HelloWorld.ps1` script in the PowerShell terminal:
```powershell
./examples/HelloWorld/HelloWorld.ps1
```
or using the `Run/Debug` on the UI

4. **Access the Pode Application:**

Once the Pode server is running, you can access your Pode application by navigating to the forwarded port provided by GitHub Codespaces. This is usually indicated by a URL in the terminal or in the Codespaces interface.

For more information on using Pode and its features, refer to the [Pode documentation](https://badgerati.github.io/Pode/).
25 changes: 21 additions & 4 deletions docs/Getting-Started/KnownIssues.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,30 @@ New-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Services\HTTP\Parameters'
## PowerShell Classes

Pode uses Runspaces to deal with multithreading and other background tasks. Due to this, PowerShell classes do not work as intended and are unsafe to use.
Pode utilizes Runspaces for multithreading and other background tasks, which makes PowerShell classes behave unpredictably and renders them unsafe to use. This is primarily because an instance of a class created in one Runspace will always be marshaled back to the original Runspace whenever it is accessed again, potentially causing Routes and Middleware to become contaminated.

You can find more information about this issue [here on PowerShell](https://github.com/PowerShell/PowerShell/issues/3651).
For more details on this issue, you can refer to the [PowerShell GitHub issue](https://github.com/PowerShell/PowerShell/issues/3651).

The crux of the issue is that if you create an instance of a class in one Runspace, then every time you try to use that instance again it will always be marshaled back to the original Runspace. This means Routes and Middleware can become contaminated.
To avoid these problems, it is recommended to use Hashtables or PSObjects instead.

It's recommended to switch to either Hashtables or PSObjects, but if you need to use classes then the following should let classes work:
However, if you need to use classes, PowerShell 7.4 introduces the `[NoRunspaceAffinity()]` attribute that makes classes thread-safe by solving this issue.

Here's an example of a class definition with the `[NoRunspaceAffinity()]` attribute:

```powershell
# Class definition with NoRunspaceAffinity attribute
[NoRunspaceAffinity()]
class SafeClass {
static [object] ShowRunspaceId($val) {
return [PSCustomObject]@{
ThreadId = [Threading.Thread]::CurrentThread.ManagedThreadId
RunspaceId = [runspace]::DefaultRunspace.Id
}
}
}
```

If you need to support versions prior to PowerShell 7.4, you can use the following approach:

* Create a module (CreateClassInstanceHelper.psm1) with the content:

Expand Down
44 changes: 40 additions & 4 deletions docs/Tutorials/Basics.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
# Basics
<sub><b>!!! Warning</b>
You can initiate only one server per PowerShell instance. To run multiple servers, start additional PowerShell, or pwsh, sessions. Each session can run its own server. This is fundamental to how Pode operates, so consider it when designing your scripts and infrastructure.</sub>

!!! warning
You can only start one server in your script


Although not required, it is recommended to import the Pode module using a maximum version, to avoid any breaking changes from new major versions:
While it’s not mandatory, we strongly recommend importing the Pode module with a specified maximum version. This practice helps to prevent potential issues arising from breaking changes introduced in new major versions:

```powershell
Import-Module -Name Pode -MaximumVersion 2.99.99
```

To further enhance the robustness of your code, consider wrapping the import statement within a try/catch block. This way, if the module fails to load, your script won’t proceed, preventing possible errors or unexpected behavior:

```powershell
try {
Import-Module -Name Pode -MaximumVersion 2.99.99
} catch {
Write-Error "Failed to load the Pode module"
throw
}
```

The script for your server should be set in the [`Start-PodeServer`](../../Functions/Core/Start-PodeServer) function, via the `-ScriptBlock` parameter. The following example will listen over HTTP on port 8080, and expose a simple HTML page of running processes at `http://localhost:8080/processes`:

```powershell
Expand Down Expand Up @@ -72,3 +82,29 @@ PS> Start-PodeServer -FilePath './File.ps1'

!!! tip
Normally when you restart your Pode server any changes to the main scriptblock don't reflect. However, if you reference a file instead, then restarting the server will reload the scriptblock from that file - so any changes will reflect.

## Internationalization

Pode has built-in support for internationalization (i18n). By default, Pode uses the `$PsUICulture` variable to determine the User Interface Culture (UICulture).

You can enforce a specific localization when importing the Pode module by using the UICulture argument. This argument accepts a culture code, which specifies the language and regional settings to use.

Here’s an example of how to enforce Korean localization:

```powershell
Import-Module -Name Pode -ArgumentList 'ko-KR'
```

In this example, 'ko-KR' is the culture code for Korean as used in South Korea. You can replace 'ko-KR' with the culture code for any other language or region.

As an alternative to specifying the UICulture when importing the Pode module, you can also change the UICulture within the PowerShell environment itself.

This can be done using the following command:

```powershell
[System.Threading.Thread]::CurrentThread.CurrentUICulture = 'ko-KR'
```

This command changes the UICulture for the current PowerShell session to Korean as used in South Korea.

Please note that this change is temporary and will only affect the current session. If you open a new PowerShell session, it will use the default UICulture.
93 changes: 93 additions & 0 deletions docs/Tutorials/CORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@

# CORS

## What is CORS?
Cross-Origin Resource Sharing (CORS) is a security feature implemented by web browsers to restrict web pages from making requests to a different domain than the one that served the web page. This is a critical aspect of web security, helping to prevent malicious sites from accessing sensitive data from another domain.

## CORS Challenges
When developing web applications, you may encounter situations where your web page needs to request resources from a different domain. This can lead to CORS errors if the appropriate headers are not set to allow these cross-origin requests. Common challenges include:
- Handling pre-flight requests.
- Allowing specific methods and headers.
- Managing credentials in cross-origin requests.
- Setting the appropriate origins.

## Addressing CORS Challenges

Pode simplifies handling CORS by providing the `Set-PodeSecurityAccessControl` function, which allows you to define the necessary headers to manage cross-origin requests effectively.

### Key Headers for CORS

1. **Access-Control-Allow-Origin**: Specifies which origins are permitted to access the resource.
2. **Access-Control-Allow-Methods**: Lists the HTTP methods that are allowed when accessing the resource.
3. **Access-Control-Allow-Headers**: Indicates which HTTP headers can be used during the actual request.
4. **Access-Control-Max-Age**: Specifies how long the results of a pre-flight request can be cached.
5. **Access-Control-Allow-Credentials**: Indicates whether credentials are allowed in the request.

### Setting CORS Headers instead

The `Set-PodeSecurityAccessControl` function allows you to set these headers easily. Here’s how you can address common CORS challenges using this function:

1. **Allowing All Origins**
```powershell
Set-PodeSecurityAccessControl -Origin '*'
```
This sets the `Access-Control-Allow-Origin` header to allow requests from any origin.

2. **Specifying Allowed Methods**
```powershell
Set-PodeSecurityAccessControl -Methods 'GET', 'POST', 'OPTIONS'
```
This sets the `Access-Control-Allow-Methods` header to allow only the specified methods.

3. **Specifying Allowed Headers**
```powershell
Set-PodeSecurityAccessControl -Headers 'Content-Type', 'Authorization'
```
This sets the `Access-Control-Allow-Headers` header to allow the specified headers.

4. **Handling Credentials**
```powershell
Set-PodeSecurityAccessControl -Credentials
```
This sets the `Access-Control-Allow-Credentials` header to allow credentials in requests.

5. **Setting Cache Duration for Pre-flight Requests**
```powershell
Set-PodeSecurityAccessControl -Duration 3600
```
This sets the `Access-Control-Max-Age` header to cache the pre-flight request for one hour.

6. **Automatic Header and Method Detection**
```powershell
Set-PodeSecurityAccessControl -AutoHeaders -AutoMethods
```
These parameters automatically populate the list of allowed headers and methods based on your OpenApi definition and defined routes, respectively.

7. **Enabling Global OPTIONS Route**
```powershell
Set-PodeSecurityAccessControl -WithOptions
```
This creates a global OPTIONS route to handle pre-flight requests automatically.

8. **Additional Security with Cross-Domain XHR Requests**
```powershell
Set-PodeSecurityAccessControl -CrossDomainXhrRequests
```
This adds the 'x-requested-with' header to the list of allowed headers, enhancing security.

### Example Configuration

Here is an example of configuring CORS settings in Pode using `Set-PodeSecurityAccessControl`:

```powershell
Set-PodeSecurityAccessControl -Origin 'https://example.com' -Methods 'GET', 'POST' -Headers 'Content-Type', 'Authorization' -Duration 7200 -Credentials -WithOptions -AutoHeaders -AutoMethods -CrossDomainXhrRequests
```

This example sets up CORS to allow requests from `https://example.com`, allows `GET` and `POST` methods, permits `Content-Type` and `Authorization` headers, enables credentials, caches pre-flight requests for two hours, automatically detects headers and methods, and allows cross-domain XHR requests.

### More Information on CORS

For more information on CORS, you can refer to the following resources:
- [Fetch Living Standard](https://fetch.spec.whatwg.org/)
- [CORS in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-7.0#credentials-in-cross-origin-requests)
- [MDN Web Docs on CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
Loading

0 comments on commit 6e69777

Please sign in to comment.