Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: installations Dart and Desktop #78

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Files and directories created by pub.
.dart_tool/
.packages

# Conventional directory for build outputs.
build/

# Omit committing pubspec.lock for library packages; see
# https://dart.dev/guides/libraries/private-files#pubspeclock.
pubspec.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 1.0.0

- Initial version.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!--
This README describes the package. If you publish this package to pub.dev,
this README's contents appear on the landing page for your package.
For information about how to write a good package README, see the guide for
[writing package pages](https://dart.dev/guides/libraries/writing-package-pages).
For general information about developing packages, see the Dart guide for
[creating packages](https://dart.dev/guides/libraries/create-library-packages)
and the Flutter guide for
[developing packages and plugins](https://flutter.dev/developing-packages).
-->

TODO: Put a short description of the package here that helps potential users
know whether this package might be useful for them.

## Features

TODO: List what your package can do. Maybe include images, gifs, or videos.

## Getting started

TODO: List prerequisites and provide or point to information on how to
start using the package.

## Usage

TODO: Include short and useful examples for package users. Add longer examples
to `/example` folder.

```dart
const like = 'sample';
```

## Additional information

TODO: Tell users more about the package: where to find more information, how to
contribute to the package, how to file issues, what response they can expect
from the package authors, and more.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.

include: package:lints/recommended.yaml

# Uncomment the following section to specify additional rules.

# linter:
# rules:
# - camel_case_types

# analyzer:
# exclude:
# - path/to/excluded/files/**

# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints

# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2022 Invertase Limited. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.

/// Support for Firebase installations API in pure Dart.
library firebase_app_installations;

import 'package:firebase_core_dart/firebase_core_dart.dart';

part 'src/firebase_app_installations.dart';
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
library api;

import 'package:firebaseapis/firebaseinstallations/v1.dart';
import 'package:googleapis_auth/auth_io.dart';
import 'package:http/http.dart' as http;

/// Configurations necessary for making all Identity Toolkit requests.
class ApiConfig {
/// Construct [ApiConfig].
ApiConfig(
this.apiKey,
this.projectId,
this.appId,
);

/// The API Key associated with the Firebase project used for initialization.
final String apiKey;

/// The project Id associated with the Firebase project used for initialization.
final String projectId;

/// The Firebase app Id of the current app.
final String appId;
}

class ApiDelegate {
ApiDelegate._(this.apiConfig, {http.Client? client}) {
_client = client ?? clientViaApiKey(apiConfig.apiKey);
}

/// Construct new or existing [API] instance for a given [APIConfig].
factory ApiDelegate.instanceOf(ApiConfig apiConfig, {http.Client? client}) {
return _instances.putIfAbsent(
apiConfig,
() => ApiDelegate._(apiConfig, client: client),
);
}

/// The Api configurations of this instance.
final ApiConfig apiConfig;

static final Map<ApiConfig, ApiDelegate> _instances = {};

late final http.Client _client;

/// [FirebaseinstallationsApi] initialized with this instance's [ApiConfig].
FirebaseinstallationsApi get installationsAPi {
return FirebaseinstallationsApi(_client);
}

Future<String?> getId() async {
final response = await installationsAPi.projects.installations.create(
GoogleFirebaseInstallationsV1Installation(appId: apiConfig.appId),
apiConfig.projectId,
);

return response.fid;
}

Future<String?> getAuthToken() async {
final response = await installationsAPi.projects.installations.create(
GoogleFirebaseInstallationsV1Installation(appId: apiConfig.appId),
apiConfig.projectId,
);

return response.fid;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
part of firebase_app_installations;

class FirebaseAppInstallationsDart {
/// The entry point for the [FirebaseAppInstallationsDart] class.
FirebaseAppInstallationsDart({FirebaseApp? app});

/// Stub initializer to allow the [registerWith] to create an instance without
/// registering the web delegates or listeners.
FirebaseAppInstallationsDart._();

/// Returns an instance of [FirebaseAppInstallationsDart].
static FirebaseAppInstallationsDart get instance {
return FirebaseAppInstallationsDart._();
}

FirebaseAppInstallationsDart instanceFor({required FirebaseApp app}) {
return FirebaseAppInstallationsDart(app: app);
}

// Future<void> delete() async {}

// Future<String> getId() async {}

// Future<String> getToken(bool forceRefresh) async {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';

final fidPattern = RegExp(r'^[cdef][\w-]{21}$');
const invalidFid = '';

/// Generates a new FID using random values.
/// Returns an empty string if FID generation fails for any reason.
String generateFid([Uint8List? byteArray]) {
try {
// A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5
// bytes. This implementation generates a 17 byte array instead.
final fidByteArray = byteArray ?? _randBytes(17);

// Replace the first 4 random bits with the constant FID header of 0b0111.
fidByteArray[0] = int.parse("01110000", radix: 2) +
(fidByteArray[0] % int.parse("00010000", radix: 2));

String fid = _encode(fidByteArray);

return fidPattern.hasMatch(fid) ? fid : invalidFid;
} catch (_) {
// FID generation errored
return invalidFid;
}
}

/// Converts a FID Uint8Array to a base64 string representation.
String _encode(Uint8List fidByteArray) {
String b64String = base64UrlEncode(fidByteArray);

// Remove the 23rd character that was added because of the extra 4 bits at the
// end of our 17 byte array, and the '=' padding.
return b64String.substring(0, 22);
}

Uint8List _randBytes(int n) {
final Random generator = Random.secure();
final Uint8List random = Uint8List(n);
for (int i = 0; i < random.length; i++) {
random[i] = generator.nextInt(255);
}
return random;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: firebase_app_installations_dart
description: Pure Dart implementation of FlutterFire Installations API
version: 1.0.0
repository: https://github.com/invertase/flutterfire_desktop

environment:
sdk: '>=2.17.0 <3.0.0'

dependencies:
crypto: ^3.0.2
firebase_core_dart: ^1.0.0
firebaseapis: ^0.1.1
googleapis_auth: ^1.1.0
http: ^0.13.4
meta: ^1.3.0
storagebox: ^0.1.0+3

dev_dependencies:
lints: ^2.0.0
test: ^1.16.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import 'generate_fid_test.dart';

void main() {
generateFidTests();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import 'dart:typed_data';

import 'package:firebase_app_installations_dart/src/helpers/generate_fid.dart';
import 'package:test/expect.dart';
import 'package:test/scaffolding.dart';

import 'mock_data.dart';

void generateFidTests() {
group(
'generateFid()',
(() {
test('deterministically generates FIDs from known random byte list', () {
for (var i = 0; i < 12; i++) {
expect(
generateFid(Uint8List.fromList(mockRandomValues[i])),
equals(expectedFids[i]),
);
}
});
test('generate valid FIDs', () {
for (var i = 0; i < 1000; i++) {
final fid = generateFid();
expect(fidPattern.hasMatch(fid), isTrue);
}
});
}),
);
}
Loading