Status: Experimental
This repo contains code for running a Fuchsia specific set of Chat modules.
- agents: Fuchsia agents (background services) using Modular APIs.
- content_provider: The chat content provider agent which communicates with the firebase DB and the Ledger instance.
- modules: Fuchsia application code using Modular APIs.
- conversation: UI module for displaying chat messages for a conversatoin.
- conversation_list: UI module for displaying the list of conversations.
- story: The primary entry point for the full Chat experience.
- services: FIDL service definitions.
This repo is already part of the default jiri manifest.
Follow the instructions for setting up a fresh Fuchsia checkout. Once you have the jiri
tool installed and have imported the default manifest and updated return to these instructions.
It is recommended you set up the Fuchsia environment helpers in scripts/env.sh
:
source scripts/env.sh
There are Makefile tasks setup to help simplify common development tasks. Use make help
to see what they are.
When you have changes you are ready to see in action you can build with:
make build
Once the system has been built you will need to run a bootserver to get it
over to a connected Acer. You can use the env.sh
helper to move the build from your host to the target device with:
freboot
Once that is done (it takes a while) you can run the application with:
make run
You can run on a connected android device with:
make flutter-run
Optional: In another terminal you can tail the logs
${FUCHSIA_DIR}/out/build-magenta/tools/loglistener
The chat modules use the Firebase Realtime Database to send and receive chat messages between users. This section describes what needs to be configured before running the chat modules correctly.
- Create a new Firebase project via the console.
- Navigate to Authentication and enable Google sign-in.
- Under "Whitelist client IDs from external projects" add the client ID for an existing OAuth application. This will allow an extra scope to be added for that app's sign-in flow enabling Google authentication and authorization for this project.
- Setup the security rules for realtime database.
-
Navigate to Database -> RULES from the Firebase console.
-
Set the security rules as follows:
{ "rules": { "emails": { "$encodedEmail": { ".read": "$encodedEmail == auth.token.email.toLowerCase().replace('.', '&2E')", ".write": "auth != null", } }, } }
This will ensure that users can send any messages to any signed up users and the messages can only be read by the designated recipients.
- Add the Firebase project information to the configuration file, so that your chat module may send messages to other users.
- Manually add the following values to
//apps/modules/common/config.json
."chat_firebase_api_key"
:<web_api_key>
"chat_firebase_project_id"
:<firebase_project_id>
- These two value can be found from your Firebase project console. Navigate to the Gear icon (upper-left side) -> Project settings.
- After adding these values, build fuchsia again, or manually copy the
config.json
file onto the fuchsia device at/system/data/modules/config.json
. - NOTE: This implies that only the chat users using the same Firebase project can talk to each other.
To run the chat agent tests, build fuchsia with --modules boot_test_modular
option and boot into fuchsia using a target device or a QEMU instance.
$ fset --modules boot_test_modular
$ fbuild
$ frun <options> # when using QEMU.
Once the fuchsia device is booted, run the following command from the host.
$ $FUCHSIA_DIR/apps/test_runner/src/run_test \
--test_file=$FUCHSIA_DIR/apps/modules/chat/tests/chat_tests.json
When the test passes, the resulting output should look like this:
Running chat_content_provider_test ..
./loglistener: listening on [::]33337 for device same-undo-rail-gains
.. pass
In case something fails, the script will output fail
, and also print out the
fuchsia console messages with more detailed error logs.
Fore more details, refer to the test_runner documentation.
(NOTE: You can ignore this section if you're only interested in running the chat app.)
There is not a Fuchsia compatible Firebase package for Dart. The following is a description of raw REST calls that the ChatContentProvider agent is doing behind the scenes to enable message transport via Firebase Realtime DB.
User authentication is managed via an existing project's login flow. For that flow to obtain to correct credentials it will need to be configured with an additional scope: "https://www.googleapis.com/auth/plus.login".
When a user authenticates a JWT is returned in the response along with the
traditional OAuth tokens. This special token, id_token
will be used in the
following call to the Google Identity Toolkit API. The following variables are
required to proceed:
export FIREBASE_KEY="<web_api_key as above>"
export FIREBASE_URL="https://<your_firebase_project_id>.firebaseio.com"
export GOOGLE_ID_TOKEN="<JWT id_token from separate OAuth process>"
The following request is required for new users of the Firebase project (identitytoolkit#VerifyAssertionResponse):
curl -Li -X POST \
-H "accept: application/json" \
-H "content-type: application/json" \
-d "{ \"postBody\": \"id_token=${GOOGLE_ID_TOKEN}&providerId=google.com\", \"requestUri\": \"http://localhost\", \"returnIdpCredential\": true, \"returnSecureToken\": true}" \
https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyAssertion?key=$FIREBASE_KEY
This call authenticates the Google API authenticated user with the Firebase project. The JSON body of the response will have this schema. Among the returned values, some useful ones include:
"localId"
: The Firebase User ID (UID) associated with this user."email"
: Primary email address for this user."idToken"
: Auth token to be used in any subsequent REST API calls to the Firebase DB.
(Not to be confused withoauthIdToken
value.)
Note that this new idToken
is different from the original GOOGLE_ID_TOKEN
we
used to make this call.
export FIREBASE_USER_ID="<'localId' value from the response>"
export FIREBASE_AUTH_TOKEN="<'idToken' value from the response>"
To grab the user's profile information use $FIREBASE_AUTH_TOKEN
with identitytoolkit#GetAccountInfo:
curl -Li -X POST \
-H "accept: application/json" \
-H "content-type: application/json" \
-d "{ \"idToken\": \"${FIREBASE_AUTH_TOKEN}\" }" \
https://www.googleapis.com/identitytoolkit/v3/relyingparty/getAccountInfo?key=$FIREBASE_KEY
This will return some useful profile data.
From here the database can be managed via the Firebase CLI or Firebase Console's web UI for defining schemas etc. For example you can create a database rule for users where only they can access their own data:
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
Once configured correctly publish the schema to the project with the Firebase CLI or the Firebase Console. From here you can start working with records.
View the user's record.
curl -Li \
-H "accept: application/json" \
$FIREBASE_URL/users/$FIREBASE_USER_ID.json?auth=$FIREBASE_AUTH_TOKEN
Update the record.
curl -Li -X PUT \
-H "accept: application/json" \
-H "content-type: application/json" \
-d "{ \"uid\": \"${FIREBASE_USER_ID}\", \"username\": \"John Doe\" }" \
$FIREBASE_URL/users/$FIREBASE_USER_ID.json?auth=$FIREBASE_AUTH_TOKEN
Stream updates.
curl -Li \
-H "accept: text/event-stream" \
$FIREBASE_URL/users/$FIREBASE_USER_ID.json?auth=$FIREBASE_AUTH_TOKEN