Skip to content

Commit 577fcbb

Browse files
authored
Test and lint (#11)
1 parent 7dec099 commit 577fcbb

File tree

14 files changed

+482
-368
lines changed

14 files changed

+482
-368
lines changed

.eslintrc.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"env": {
3+
"browser": true,
4+
"commonjs": true,
5+
"es6": true,
6+
"node": true,
7+
"mocha": true
8+
},
9+
"extends": "eslint:recommended",
10+
"parserOptions": {
11+
"sourceType": "module"
12+
},
13+
"rules": {
14+
"indent": [
15+
"error",
16+
4
17+
],
18+
"linebreak-style": [
19+
"error",
20+
"unix"
21+
],
22+
"quotes": [
23+
"error",
24+
"single"
25+
],
26+
"semi": [
27+
"error",
28+
"always"
29+
],
30+
"no-console": 0,
31+
"no-unused-vars": 0
32+
}
33+
}

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
node_modules
22
keyfile.json
3+
service-account.json
34

45
.firebaserc
5-
firebase.json
6+
firebase.json
7+
8+
package-lock.json
9+
lerna-debug.log

.travis.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
language: node_js
2+
node_js:
3+
- "7"
4+
before_install:
5+
- openssl aes-256-cbc -K $encrypted_001d217edcb2_key -iv $encrypted_001d217edcb2_iv -in service-account.json.enc -out service-account.json -d
6+
install:
7+
- npm install -g lerna
8+
- npm install -g eslint
9+
- lerna bootstrap
10+
script:
11+
- ./scripts/test.sh

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,7 @@ on [firebase.google.com](https://firebase.google.com/docs/).
66
## Contributing
77

88
We love contributions! See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
9+
10+
## Build Status
11+
12+
[![Build Status](https://travis-ci.org/firebase/snippets-node.svg?branch=master)](https://travis-ci.org/firebase/snippets-node)

auth/get_service_account_tokens.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ const serviceAccount = require('path/to/serviceAccountKey.json');
2121
const credential = admin.credential.cert(serviceAccount);
2222

2323
credential.getAccessToken().then((accessTokenInfo) => {
24-
const accessToken = accessTokenInfo.access_token;
25-
const expirationTime = accessTokenInfo.expires_in;
24+
const accessToken = accessTokenInfo.access_token;
25+
const expirationTime = accessTokenInfo.expires_in;
2626

27-
// Attach accessToken to HTTPS request in the "Authorization: Bearer" header
28-
// After expirationTime, you must generate a new access token
29-
// [START_EXCLUDE]
30-
console.log(`The token ${accessToken} expires in ${expirationTime}`);
31-
// [END_EXCLUDE]
27+
// Attach accessToken to HTTPS request in the "Authorization: Bearer" header
28+
// After expirationTime, you must generate a new access token
29+
// [START_EXCLUDE]
30+
console.log(`The token ${accessToken} expires in ${expirationTime}`);
31+
// [END_EXCLUDE]
3232
});
3333
// [END get_service_account_tokens]
3434

firestore/full-text-search/functions/index.js

Lines changed: 55 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ const client = algoliasearch(ALGOLIA_ID, ALGOLIA_ADMIN_KEY);
3232
// [START update_index_function]
3333
// Update the search index every time a blog post is written.
3434
exports.onNoteCreated = functions.firestore.document('notes/{noteId}').onCreate(event => {
35-
// Get the note document
36-
const note = event.data.data();
35+
// Get the note document
36+
const note = event.data.data();
3737

38-
// Add an 'objectID' field which Algolia requires
39-
note.objectID = event.params.noteId;
38+
// Add an 'objectID' field which Algolia requires
39+
note.objectID = event.params.noteId;
4040

41-
// Write to the algolia index
42-
const index = client.initIndex(ALGOLIA_INDEX_NAME);
43-
return index.saveObject(note);
41+
// Write to the algolia index
42+
const index = client.initIndex(ALGOLIA_INDEX_NAME);
43+
return index.saveObject(note);
4444
});
4545
// [END update_index_function]
4646

@@ -49,40 +49,39 @@ const admin = require('firebase-admin');
4949
admin.initializeApp(functions.config().firebase);
5050

5151
function getFirebaseUser(req, res, next) {
52-
console.log('Check if request is authorized with Firebase ID token');
53-
54-
if (!req.headers.authorization
55-
|| !req.headers.authorization.startsWith('Bearer ')) {
56-
console.error(
57-
'No Firebase ID token was passed as a Bearer token in the Authorization header.',
58-
'Make sure you authorize your request by providing the following HTTP header:',
59-
'Authorization: Bearer <Firebase ID Token>'
60-
);
61-
res.status(403).send('Unauthorized');
62-
return;
63-
}
64-
65-
let idToken;
66-
if (
67-
req.headers.authorization &&
68-
req.headers.authorization.startsWith('Bearer ')
69-
) {
70-
console.log('Found 'Authorization' header');
71-
idToken = req.headers.authorization.split('Bearer ')[1];
72-
}
73-
74-
admin
75-
.auth()
76-
.verifyIdToken(idToken)
77-
.then(decodedIdToken => {
78-
console.log('ID Token correctly decoded', decodedIdToken);
79-
req.user = decodedIdToken;
80-
next();
81-
})
82-
.catch(error => {
83-
console.error('Error while verifying Firebase ID token:', error);
84-
res.status(403).send('Unauthorized');
85-
});
52+
console.log('Check if request is authorized with Firebase ID token');
53+
54+
if (!req.headers.authorization
55+
|| !req.headers.authorization.startsWith('Bearer ')) {
56+
console.error(
57+
'No Firebase ID token was passed as a Bearer token in the Authorization header.',
58+
'Make sure you authorize your request by providing the following HTTP header:',
59+
'Authorization: Bearer <Firebase ID Token>'
60+
);
61+
res.status(403).send('Unauthorized');
62+
return;
63+
}
64+
65+
let idToken;
66+
if (
67+
req.headers.authorization &&
68+
req.headers.authorization.startsWith('Bearer ')
69+
) {
70+
console.log('Found \'Authorization\' header');
71+
idToken = req.headers.authorization.split('Bearer ')[1];
72+
}
73+
74+
admin
75+
.auth()
76+
.verifyIdToken(idToken)
77+
.then(decodedIdToken => {
78+
console.log('ID Token correctly decoded', decodedIdToken);
79+
req.user = decodedIdToken;
80+
next();
81+
}).catch(error => {
82+
console.error('Error while verifying Firebase ID token:', error);
83+
res.status(403).send('Unauthorized');
84+
});
8685
}
8786
// [END get_firebase_user]
8887

@@ -101,22 +100,22 @@ app.use(require('cors')({ origin: true }));
101100
// https://gist.github.com/abehaskins/832d6f8665454d0cd99ef08c229afb42
102101
app.use(getFirebaseUser);
103102

104-
// Add a route handler to the app to generate the secured key
103+
// Add a route handler to the app to generate the secured key
105104
app.get('/', (req, res) => {
106-
// Create the params object as described in the Algolia documentation:
107-
// https://www.algolia.com/doc/guides/security/api-keys/#generating-api-keys
108-
const params = {
109-
// This filter ensures that only documents where author == user_id will be readable
110-
filters: `author:${req.user.user_id}`,
111-
// We also proxy the user_id as a unique token for this key.
112-
userToken: req.user.user_id
113-
};
114-
115-
// Call the Algolia API to generate a unique key based on our search key
116-
const key = client.generateSecuredApiKey(ALGOLIA_SEARCH_KEY, params);
117-
118-
// Then return this key as {key: '...key'}
119-
res.json({ key });
105+
// Create the params object as described in the Algolia documentation:
106+
// https://www.algolia.com/doc/guides/security/api-keys/#generating-api-keys
107+
const params = {
108+
// This filter ensures that only documents where author == user_id will be readable
109+
filters: `author:${req.user.user_id}`,
110+
// We also proxy the user_id as a unique token for this key.
111+
userToken: req.user.user_id
112+
};
113+
114+
// Call the Algolia API to generate a unique key based on our search key
115+
const key = client.generateSecuredApiKey(ALGOLIA_SEARCH_KEY, params);
116+
117+
// Then return this key as {key: '...key'}
118+
res.json({ key });
120119
});
121120

122121
// Finally, pass our ExpressJS app to Cloud Functions as a function
Lines changed: 59 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,59 @@
1-
// [START search_index_unsecure]
2-
const client = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_SEARCH_KEY);
3-
const index = client.initIndex("notes");
4-
5-
// Search query
6-
const query = "Some text";
7-
8-
// Perform an Algolia search:
9-
// https://www.algolia.com/doc/api-reference/api-methods/search/
10-
index
11-
.search({
12-
query
13-
})
14-
.then(responses => {
15-
// Response from Algolia:
16-
// https://www.algolia.com/doc/api-reference/api-methods/search/#response-format
17-
console.log(responses.hits);
18-
});
19-
// [END search_index_unsecure]
20-
21-
// [START search_index_secure]
22-
const projectID = "YOUR_PROJECT_ID";
23-
24-
// Search query
25-
const query = "Some text";
26-
27-
// Use Firebase Authentication to request the underlying token
28-
firebase.auth().currentUser.getIdToken()
29-
.then(token => {
30-
// The token is then passed to our getSearchKey Cloud Function
31-
return fetch(`https://us-central1-${projectID}.cloudfunctions.net/getSearchKey/`, {
32-
headers: { Authorization: `Bearer ${token}` }
33-
});
34-
})
35-
.then(r => {
36-
// The Fetch API returns a stream, which we convert into a JSON object.
37-
return r.json();
38-
})
39-
.then(data => {
40-
// Data will contain the restricted key in the `key` field.
41-
this.algolia.client = algoliasearch(ALGOLIA_APP_ID, data.key);
42-
this.algolia.index = this.algolia.client.initIndex("notes");
43-
44-
// Perform the search as usual.
45-
return index.search({query});
46-
})
47-
.then(responses => {
48-
console.log(responses.hits);
49-
});
50-
// [END search_index_secure]
1+
const algoliasearch = require('algoliasearch');
2+
const ALGOLIA_APP_ID = 'YOUR_APP_ID';
3+
const ALGOLIA_SEARCH_KEY = 'YOUR_SEARCH_KEY';
4+
5+
// To pass lint only
6+
const firebase = undefined;
7+
let index = undefined;
8+
9+
function searchIndexUnsecure() {
10+
// [START search_index_unsecure]
11+
const client = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_SEARCH_KEY);
12+
const index = client.initIndex('notes');
13+
14+
// Search query
15+
const query = 'Some text';
16+
17+
// Perform an Algolia search:
18+
// https://www.algolia.com/doc/api-reference/api-methods/search/
19+
index
20+
.search({
21+
query
22+
})
23+
.then(responses => {
24+
// Response from Algolia:
25+
// https://www.algolia.com/doc/api-reference/api-methods/search/#response-format
26+
console.log(responses.hits);
27+
});
28+
// [END search_index_unsecure]
29+
}
30+
31+
function searchIndexSecure() {
32+
// [START search_index_secure]
33+
const projectID = 'YOUR_PROJECT_ID';
34+
35+
// Search query
36+
const query = 'Some text';
37+
38+
// Use Firebase Authentication to request the underlying token
39+
firebase.auth().currentUser.getIdToken()
40+
.then(token => {
41+
// The token is then passed to our getSearchKey Cloud Function
42+
return fetch(`https://us-central1-${projectID}.cloudfunctions.net/getSearchKey/`, {
43+
headers: { Authorization: `Bearer ${token}` }
44+
});
45+
}).then(r => {
46+
// The Fetch API returns a stream, which we convert into a JSON object.
47+
return r.json();
48+
}).then(data => {
49+
// Data will contain the restricted key in the `key` field.
50+
this.algolia.client = algoliasearch(ALGOLIA_APP_ID, data.key);
51+
this.algolia.index = this.algolia.client.initIndex('notes');
52+
53+
// Perform the search as usual.
54+
return index.search({query});
55+
}).then(responses => {
56+
console.log(responses.hits);
57+
});
58+
// [END search_index_secure]
59+
}

0 commit comments

Comments
 (0)