mirror of
https://github.com/flutter/holobooth.git
synced 2025-05-17 13:25:59 +08:00
feat: adding production environment config (#317)
* feat: adding production config files * better handling prod and dev environments * small fixes and changes regarding prod * fixing domains * feat: fixing config functions host * feat: properly loading firebase options depending on the env * adding final prod domain url * fix: lint
This commit is contained in:
10
.firebaserc
10
.firebaserc
@ -1,8 +1,16 @@
|
||||
{
|
||||
"projects": {
|
||||
"default": "io-photobooth-dev"
|
||||
"default": "io-photobooth-dev",
|
||||
"production": "holobooth-prod"
|
||||
},
|
||||
"targets": {
|
||||
"holobooth-prod": {
|
||||
"hosting": {
|
||||
"app_prod": [
|
||||
"0cf34931-6ab3-8cd9-57b5-f38b5fa5ba1e"
|
||||
]
|
||||
}
|
||||
},
|
||||
"io-photobooth-dev": {
|
||||
"hosting": {
|
||||
"app_dev": [
|
||||
|
2
.github/workflows/deploy_app_dev.yaml
vendored
2
.github/workflows/deploy_app_dev.yaml
vendored
@ -16,7 +16,7 @@ jobs:
|
||||
flutter-version: "3.6.0-0.1.pre"
|
||||
channel: "beta"
|
||||
- run: flutter packages get
|
||||
- run: flutter build web --web-renderer canvaskit
|
||||
- run: flutter build web --web-renderer canvaskit -t lib/main_dev.dart
|
||||
- uses: FirebaseExtended/action-hosting-deploy@v0
|
||||
with:
|
||||
repoToken: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
26
.github/workflows/deploy_app_production.yaml
vendored
Normal file
26
.github/workflows/deploy_app_production.yaml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
name: deploy_app_production
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy-dev:
|
||||
runs-on: ubuntu-latest
|
||||
name: Deploy App Production
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: "3.6.0-0.1.pre"
|
||||
channel: "beta"
|
||||
- run: flutter packages get
|
||||
- run: flutter build web --web-renderer canvaskit -t lib/main_prod.dart
|
||||
- uses: FirebaseExtended/action-hosting-deploy@v0
|
||||
with:
|
||||
repoToken: "${{ secrets.GITHUB_TOKEN }}"
|
||||
firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_PHOTOBOOTH_PRODUCTION }}"
|
||||
projectId: holobooth-prod
|
||||
target: app_prod
|
||||
expires: 30d
|
||||
channelId: live
|
||||
|
2
.github/workflows/deploy_app_staging.yaml
vendored
2
.github/workflows/deploy_app_staging.yaml
vendored
@ -14,7 +14,7 @@ jobs:
|
||||
flutter-version: "3.6.0-0.1.pre"
|
||||
channel: "beta"
|
||||
- run: flutter packages get
|
||||
- run: flutter build web --web-renderer canvaskit
|
||||
- run: flutter build web --web-renderer canvaskit -t lib/main_dev.dart
|
||||
- uses: FirebaseExtended/action-hosting-deploy@v0
|
||||
with:
|
||||
repoToken: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
@ -22,7 +22,7 @@ A Photo Booth built with [Flutter][flutter_link] and [Firebase][firebase_link] f
|
||||
To run the desired project either use the launch configuration in VSCode/Android Studio or use the following commands:
|
||||
|
||||
```sh
|
||||
$ flutter run -d chrome
|
||||
$ flutter run -d chrome -t lib/main_dev.dart
|
||||
```
|
||||
|
||||
_\*I/O Photo Booth works on Web._
|
||||
|
@ -1,7 +1,8 @@
|
||||
include: package:very_good_analysis/analysis_options.3.1.0.yaml
|
||||
analyzer:
|
||||
exclude:
|
||||
- lib/firebase_options.dart
|
||||
- lib/firebase_options_dev.dart
|
||||
- lib/firebase_options_prod.dart
|
||||
- lib/**/*.gen.dart
|
||||
linter:
|
||||
rules:
|
||||
|
@ -99,6 +99,56 @@
|
||||
}
|
||||
],
|
||||
"predeploy": []
|
||||
},
|
||||
{
|
||||
"target": "app_prod",
|
||||
"public": "build/web",
|
||||
"cleanUrls": true,
|
||||
"trailingSlash": false,
|
||||
"ignore": [
|
||||
".firebase",
|
||||
"firebase.json",
|
||||
"functions/node_modules",
|
||||
"functions/src",
|
||||
"__/**"
|
||||
],
|
||||
"rewrites": [
|
||||
{ "source": "/share/**", "function": "shareImage" },
|
||||
{
|
||||
"source": "**",
|
||||
"destination": "/index.html"
|
||||
}
|
||||
],
|
||||
"headers": [
|
||||
{
|
||||
"source": "**/*.@(eot|otf|ttf|ttc|woff|font.css)",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Access-Control-Allow-Origin",
|
||||
"value": "*"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "**/*.@(jpg|jpeg|gif|png)",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "max-age=3600"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "**",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "no-cache, no-store, must-revalidate"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"predeploy": []
|
||||
}
|
||||
],
|
||||
"functions": {
|
||||
|
@ -2,11 +2,11 @@ export const ENV = process.env.NODE_ENV;
|
||||
export const UPLOAD_PATH = 'uploads';
|
||||
export const SHARE_PATH = 'share';
|
||||
export const ALLOWED_HOSTS = [
|
||||
'localhost:5001',
|
||||
'io-photobooth-dev.web.app',
|
||||
'io-photo-booth.web.app',
|
||||
'us-central1-io-photobooth-dev.cloudfunctions.net',
|
||||
'us-central1-io-photo-booth.cloudfunctions.net',
|
||||
'photobooth.flutter.dev',
|
||||
'convert-it4sycsdja-uc.a.run.app',
|
||||
'http://localhost:5001',
|
||||
'https://io-photobooth-dev.web.app',
|
||||
'https://io-photo-booth.web.app',
|
||||
'https://photobooth.flutter.dev',
|
||||
'https://holobooth-prod.web.app',
|
||||
'https://0cf34931-6ab3-8cd9-57b5-f38b5fa5ba1e.web.app',
|
||||
'https://holobooth.flutter.dev',
|
||||
];
|
||||
|
@ -205,7 +205,7 @@ jest.mock('firebase-admin', () => {
|
||||
describe('convert', () => {
|
||||
it('returns response with status 200 on success', async () => {
|
||||
const mockRequest = mockDeep<functions.https.Request>();
|
||||
mockRequest.get.mockReturnValue('localhost:5001');
|
||||
mockRequest.get.mockReturnValue('http://localhost:5001');
|
||||
mockRequest.protocol = 'https';
|
||||
setUpBusboy('finish', 'end');
|
||||
setUpFfmpeg('end');
|
||||
@ -228,7 +228,7 @@ describe('convert', () => {
|
||||
|
||||
it('returns status 500 on error', async () => {
|
||||
const mockRequest = mockDeep<functions.https.Request>();
|
||||
mockRequest.get.mockReturnValue('localhost:5001');
|
||||
mockRequest.get.mockReturnValue('http://localhost:5001');
|
||||
mockRequest.protocol = 'https';
|
||||
setUpBusboy('error', 'error');
|
||||
|
||||
@ -254,7 +254,7 @@ describe('convertImages', () => {
|
||||
|
||||
it('returns response with status 200 and file url on success', async () => {
|
||||
const mockRequest = mockDeep<functions.https.Request>();
|
||||
mockRequest.get.mockReturnValue('localhost:5001');
|
||||
mockRequest.get.mockReturnValue('http://localhost:5001');
|
||||
mockRequest.protocol = 'https';
|
||||
|
||||
setUpBusboy('finish', 'end');
|
||||
|
@ -51,13 +51,11 @@ export async function convertImages(
|
||||
let tempDir: string | null = null;
|
||||
|
||||
try {
|
||||
const host = req.get('host') ?? '';
|
||||
const baseUrl = `${req.protocol}://${host}`;
|
||||
const host = req.get('origin') ?? '';
|
||||
|
||||
if (!ALLOWED_HOSTS.includes(host)) {
|
||||
functions.logger.log('Bad host', {
|
||||
host,
|
||||
baseUrl,
|
||||
});
|
||||
throw new Error('Bad host');
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ describe('Share API', () => {
|
||||
path: '',
|
||||
protocol: 'http',
|
||||
get(_: string) {
|
||||
return 'localhost:5001';
|
||||
return 'http://localhost:5001';
|
||||
},
|
||||
} as functions.https.Request;
|
||||
|
||||
|
@ -12,11 +12,13 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:io_photobooth/app/app.dart';
|
||||
import 'package:io_photobooth/app/app_bloc_observer.dart';
|
||||
import 'package:io_photobooth/firebase_options.dart';
|
||||
import 'package:io_photobooth/landing/loading_indicator_io.dart'
|
||||
if (dart.library.html) 'package:io_photobooth/landing/loading_indicator_web.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
Future<void> bootstrap({
|
||||
required String convertUrl,
|
||||
required FirebaseOptions firebaseOptions,
|
||||
}) async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
Bloc.observer = AppBlocObserver();
|
||||
FlutterError.onError = (details) {
|
||||
@ -25,7 +27,7 @@ Future<void> main() async {
|
||||
};
|
||||
|
||||
await Firebase.initializeApp(
|
||||
options: DefaultFirebaseOptions.currentPlatform,
|
||||
options: firebaseOptions,
|
||||
);
|
||||
|
||||
final authenticationRepository = AuthenticationRepository(
|
||||
@ -35,7 +37,7 @@ Future<void> main() async {
|
||||
|
||||
final avatarDetectorRepository = AvatarDetectorRepository();
|
||||
final convertRepository = ConvertRepository(
|
||||
url: 'https://convert-it4sycsdja-uc.a.run.app',
|
||||
url: convertUrl,
|
||||
);
|
||||
|
||||
runZonedGuarded(
|
64
lib/firebase_options_prod.dart
Normal file
64
lib/firebase_options_prod.dart
Normal file
@ -0,0 +1,64 @@
|
||||
// File generated by FlutterFire CLI.
|
||||
// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members
|
||||
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
||||
import 'package:flutter/foundation.dart'
|
||||
show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
||||
|
||||
/// Default [FirebaseOptions] for use with your Firebase apps.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// import 'firebase_options.dart';
|
||||
/// // ...
|
||||
/// await Firebase.initializeApp(
|
||||
/// options: DefaultFirebaseOptions.currentPlatform,
|
||||
/// );
|
||||
/// ```
|
||||
class DefaultFirebaseOptions {
|
||||
static FirebaseOptions get currentPlatform {
|
||||
if (kIsWeb) {
|
||||
return web;
|
||||
}
|
||||
switch (defaultTargetPlatform) {
|
||||
case TargetPlatform.android:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for android - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.iOS:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for ios - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.macOS:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for macos - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.windows:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for windows - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.linux:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for linux - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
default:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions are not supported for this platform.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static const FirebaseOptions web = FirebaseOptions(
|
||||
apiKey: 'AIzaSyAJJhkSV4Mn2Yk4XhGc2Keitfy-iGRTXfQ',
|
||||
appId: '1:2414555761:web:e13eb13e7dfd4b277561d0',
|
||||
messagingSenderId: '2414555761',
|
||||
projectId: 'holobooth-prod',
|
||||
authDomain: 'holobooth-prod.firebaseapp.com',
|
||||
storageBucket: 'holobooth-prod.appspot.com',
|
||||
measurementId: 'G-KWF3BR55Z5',
|
||||
);
|
||||
}
|
10
lib/main_dev.dart
Normal file
10
lib/main_dev.dart
Normal file
@ -0,0 +1,10 @@
|
||||
import 'package:io_photobooth/bootstrap.dart';
|
||||
import 'package:io_photobooth/firebase_options_dev.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
const convertUrl = 'https://convert-it4sycsdja-uc.a.run.app';
|
||||
await bootstrap(
|
||||
convertUrl: convertUrl,
|
||||
firebaseOptions: DefaultFirebaseOptions.currentPlatform,
|
||||
);
|
||||
}
|
10
lib/main_prod.dart
Normal file
10
lib/main_prod.dart
Normal file
@ -0,0 +1,10 @@
|
||||
import 'package:io_photobooth/bootstrap.dart';
|
||||
import 'package:io_photobooth/firebase_options_prod.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
const convertUrl = 'https://convert-fge4q4vwia-uc.a.run.app';
|
||||
await bootstrap(
|
||||
convertUrl: convertUrl,
|
||||
firebaseOptions: DefaultFirebaseOptions.currentPlatform,
|
||||
);
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
rules_version = '2';
|
||||
service firebase.storage {
|
||||
match /b/{bucket}/o {
|
||||
match /{folder}/{imageId} {
|
||||
allow read: if imageId.matches(".*\\.png") || imageId.matches(".*\\.jpg");
|
||||
allow write: if false;
|
||||
match /{allPaths=**} {
|
||||
allow create: if request.auth != null;
|
||||
allow read: if true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user