Skip to content

Commit 87e6b91

Browse files
authored
Merge pull request #24 from InnovationMinds/main
feat(cache): enhance Redis cache configuration with ACL and TLS support
2 parents 46c12ba + 5ded2cf commit 87e6b91

4 files changed

Lines changed: 70 additions & 11 deletions

File tree

apps/docs/docs/cache.mdx

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ The **Expo Open OTA server** uses a cache to improve performance and reduce serv
1212
The cache is primarily used for:
1313

1414
1. **Storing the computed `lastUpdateId` for a given platform and runtime version**
15+
1516
- This prevents the need to recompute the last update for every request, significantly speeding up responses.
1617

1718
2. **Caching the computed manifest**
@@ -22,19 +23,20 @@ The cache is primarily used for:
2223
The environment variables required for each storage solution are listed below, you can set them in a `.env` file in the root of the project or keep them in a safe place to prepare for deployment.
2324
:::
2425

25-
import Tabs from '@theme/Tabs';
26-
import TabItem from '@theme/TabItem';
26+
import Tabs from "@theme/Tabs";
27+
import TabItem from "@theme/TabItem";
2728

2829
<Tabs queryString="cache" defaultValue="local">
2930
<TabItem value="local" label="Local cache" default>
3031
:::warning
3132

32-
This cache solution is not recommended for production use. It is intended for development and testing purposes only.
33-
If you really want to use it in production, make sure to not have multiple instances of the server running, as the cache is stored locally and not shared between instances.
33+
This cache solution is not recommended for production use. It is intended for development and testing purposes only.
34+
If you really want to use it in production, make sure to not have multiple instances of the server running, as the cache is stored locally and not shared between instances.
35+
36+
:::
37+
Local cache is the default cache solution used by the server. It stores the cache in memory and is not shared between instances of the server. This means that the cache is lost when the server is restarted.
38+
No additional configuration is required to use the local cache.
3439

35-
:::
36-
Local cache is the default cache solution used by the server. It stores the cache in memory and is not shared between instances of the server. This means that the cache is lost when the server is restarted.
37-
No additional configuration is required to use the local cache.
3840
</TabItem>
3941
<TabItem value="redis" label="Redis">
4042
To use Redis as your cache solution, you need to set the following environment variables:
@@ -43,6 +45,26 @@ import TabItem from '@theme/TabItem';
4345
REDIS_PORT=your-redis-port
4446
REDIS_PASSWORD=your-redis-password
4547
REDIS_USE_TLS=true // optional if you are using a TLS connection
48+
REDIS_USERNAME=your-redis-username // optional for ACL authentication
49+
REDIS_CA_CERT_B64=base64-encoded-ca-certificate // optional for TLS with custom CA
4650
```
51+
52+
:::tip TLS/SSL Configuration
53+
54+
If you're using Redis with TLS/SSL and a custom CA certificate:
55+
- Set `REDIS_USE_TLS=true`
56+
- Set `REDIS_CA_CERT_B64` to your base64-encoded PEM certificate
57+
- To encode your certificate: `cat certificate.pem | base64 -w 0`
58+
59+
:::
60+
61+
:::info ACL Authentication
62+
63+
If your Redis server uses ACL (Access Control Lists):
64+
- Set `REDIS_USERNAME` to your Redis username
65+
- Ensure `REDIS_PASSWORD` is set to the corresponding password
66+
67+
:::
68+
4769
</TabItem>
4870
</Tabs>

apps/docs/docs/environment.mdx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ You can set these variables in a `.env` file for local development or in your de
3333
| `REDIS_HOST` | ✅ if CACHE_MODE = `redis` | Redis host | `127.0.0.1` | [Ref](/docs/cache?cache=redis) |
3434
| `REDIS_PORT` | ✅ if CACHE_MODE = `redis` | Redis port | `6379` | [Ref](/docs/cache?cache=redis) |
3535
| `REDIS_PASSWORD` | ✅ if CACHE_MODE = `redis` | Redis password | `password` | [Ref](/docs/cache?cache=redis) |
36-
36+
| `REDIS_USE_TLS` || Enable TLS/SSL connection | `true` | [Ref](/docs/cache?cache=redis) |
37+
| `REDIS_USERNAME` || Redis username for ACL authentication | `myuser` | [Ref](/docs/cache?cache=redis) |
38+
| `REDIS_CA_CERT_B64` || Base64-encoded CA certificate for TLS | `Base64 string` | [Ref](/docs/cache?cache=redis) |
3739

3840
### 📦 **Storage Configuration**
3941
| Name | Required | Description | Example | Reference |

internal/cache/cache.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ func GetCache() Cache {
5656
password := config.GetEnv("REDIS_PASSWORD")
5757
port := config.GetEnv("REDIS_PORT")
5858
useTLS := config.GetEnv("REDIS_USE_TLS") == "true"
59-
cacheInstance = NewRedisCache(host, password, port, useTLS)
59+
// ACL and TLS configuration
60+
username := config.GetEnv("REDIS_USERNAME")
61+
caCertB64 := config.GetEnv("REDIS_CA_CERT_B64")
62+
cacheInstance = NewRedisCache(host, password, port, useTLS, username, caCertB64)
6063
default:
6164
panic("Unknown cache type")
6265
}

internal/cache/redisCache.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ package cache
33
import (
44
"context"
55
"crypto/tls"
6+
"crypto/x509"
7+
"encoding/base64"
68
"errors"
79
"fmt"
10+
"log"
811
"time"
912

1013
"github.com/redis/go-redis/v9"
@@ -17,14 +20,43 @@ type RedisCache struct {
1720
port string
1821
}
1922

20-
func NewRedisCache(host, password, port string, useTLS bool) *RedisCache {
23+
func NewRedisCache(host, password, port string, useTLS bool, username, caCertB64 string) *RedisCache {
2124
opts := &redis.Options{
2225
Addr: host + ":" + port,
2326
Password: password,
2427
}
2528

29+
// Configure ACL username if provided
30+
if username != "" {
31+
opts.Username = username
32+
}
33+
34+
// Configure TLS/SSL
2635
if useTLS {
27-
opts.TLSConfig = &tls.Config{}
36+
tlsConfig := &tls.Config{
37+
MinVersion: tls.VersionTLS12,
38+
}
39+
40+
// Load CA certificate if provided
41+
if caCertB64 != "" {
42+
// Decode base64 certificate
43+
caCertPEM, err := base64.StdEncoding.DecodeString(caCertB64)
44+
if err != nil {
45+
log.Printf("Failed to decode CA certificate from base64: %v", err)
46+
log.Printf("WARNING: Proceeding with TLS connection without custom CA certificate")
47+
} else {
48+
// Create certificate pool and add CA certificate
49+
certPool := x509.NewCertPool()
50+
if !certPool.AppendCertsFromPEM(caCertPEM) {
51+
log.Printf("Failed to append CA certificate to pool")
52+
log.Printf("WARNING: Proceeding with TLS connection without custom CA certificate")
53+
} else {
54+
tlsConfig.RootCAs = certPool
55+
}
56+
}
57+
}
58+
59+
opts.TLSConfig = tlsConfig
2860
}
2961

3062
client := redis.NewClient(opts)

0 commit comments

Comments
 (0)