Authenticating Firebase with Angular.js and $.authwithPassword() - firebase

I'm attempting the following code. I'm able to authenticate a user by email/password when clicking "login", and get an object returned; but I don't understand what I'm missing to return the data that I'm trying to get from "items" and "alseCards". If I set the read and write to "true" they return data fine, just want to authenticate those with any user who is logged in.
I feel it's Security/Rule setting, but just getting started with Firebase and struggling.
index.html
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="https://cdn.firebase.com/js/client/2.2.7/firebase.js"></script>
<script src="https://cdn.firebase.com/libs/angularfire/1.1.2/angularfire.min.js"></script>
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
</head>
<body ng-controller="controller">
<div>
<button ng-click="login()">Login</button>
<p ng-if="authData">Logged in user: <strong>{{ authData.uid }}</strong>
</p>
<p ng-if="error">Error: <strong>{{ error }}</strong>
</p>
</div>
<h1>Items</h1>
<ul id="items">
<li ng-repeat="item in items">
<h2>{{item.$id}}</h2>
<ul id="inspections">
<li ng-repeat="inspection in item.inspections">{{inspection.description}} on {{inspection.timeStamp}} by {{inspection.inspector}}</li>
</ul>
</li>
</ul>
<script>
</script>
<script>
var app = angular.module("app", ["firebase"]);
app.controller("controller", ["$scope", "$firebaseArray", "$firebaseAuth",
function($scope, $firebaseArrary, $firebaseAuth) {
var ref = new Firebase("https://<-testing->.firebaseio.com");
var auth = $firebaseAuth(ref);
$scope.login = function() {
$scope.authData = null;
$scope.error = null;
auth.$authWithPassword({
email: "email#myemail.com",
password: "alseTest"
}).then(function(authData) {
console.log(authData)
$scope.authData = authData;
}).
catch (function(error) {
$scope.error = error;
});
};
$scope.alseCards = $firebaseArrary(ref.child("alseCards"));
$scope.items = $firebaseArrary(ref.child("items"));
}
]);
</script>
</body>
Security and Rules.json
{
"rules": {
"users": {"$user_id": {".write": "$user_id === auth.uid", ".read": "$user_id === auth.uid"}},
"items": {".write": "auth !== null && auth.provider === 'password'", ".read": "auth !== null && auth.provider === 'password'"},
"alseCards": {".write": "auth !== null && auth.provider === 'password'", ".read": "auth !== null && auth.provider === 'password'"}
}
}
Thanks ahead of time.

I think the problem is you have the code to get your items and alseCards outside the login function. This means it gets executed when the controller is first called and at that time the user hasn't logged in yet. Try to put it inside the login function like this:
$scope.login = function() {
$scope.authData = null;
$scope.error = null;
auth.$authWithPassword({
email: "email#myemail.com",
password: "alseTest"
}).then(function(authData) {
console.log(authData)
$scope.authData = authData;
$scope.alseCards = $firebaseArrary(ref.child("alseCards"));
$scope.items = $firebaseArrary(ref.child("items"));
}).
catch(function(error) {
$scope.error = error;
});
};

Related

Is it possible to check if already value then not set that field?

I setData after login successfully. All values are null except phone number. after that user can edit profile and set displayName and email and other fields. but all fields are again null when the user logs out and log in.
Is it possible to check if already value then not set that field?
Future<void> addUser(UserModel model){
return _db.collection('users').document(model.uid).setData({
'displayName':model.displayName,
'email':model.email,
'phone':model.phone,
'photoUrl':model.photoUrl,
'title':model.title,
'vendorCircle':model.vendorCircle,
'type':model.type,
},merge: true);
}
Solution
Future<void> addUser(UserModel model) {
if (model.photoUrl != '' &&
model.email != '' &&
model.displayName != '' &&
model.title != '' &&
model.vendorCircle != '') {
return _db.collection('users').document(model.uid).setData({
'displayName': model.displayName,
'email': model.email,
'phone': model.phone,
'photoUrl': model.photoUrl,
'title': model.title,
'vendorCircle': model.vendorCircle,
'type': model.type,
}, merge: true);
} else if (model.email != '' &&
model.displayName != '' &&
model.vendorCircle != ''){
return _db.collection('users').document(model.uid).setData({
'displayName': model.displayName,
'email': model.email,
'phone': model.phone,
'vendorCircle': model.vendorCircle,
'type':model.type
}, merge: true);
}else{
return _db.collection('users').document(model.uid).setData({
'phone': model.phone,
'type':model.type
}, merge: true);
}
}
Setting a null value on a field is precisely the operation you're asking for: it sets null on that field. There is no configuration option on Firestore to change that behavior.
What you can do is build the model conditionally on the Flutter/Dart side. Something like:
var data = {
'displayName':model.displayName,
'email':model.email,
'phone':model.phone,
'photoUrl':model.photoUrl,
'title':model.title,
'vendorCircle':model.vendorCircle,
'type':model.type,
};
data.removeWhere((k,v) => v == null);
_db.collection('users').document(model.uid).setData(data, merge: true);
Inspired by this comment on github and the documentation of the removeWhere method.

Writing operation fails - firebase database rules

I have the following object:
const offer = {
offerInfo: {
price: '',
status: 'open',
message: '',
ownerUID: '',
ownerName: '',
ownerPhoto: '',
ownerAvgRating: '',
ownerReviewNumber: '',
},
offerMetaData: {
userHasSeenOffer: false,
userHasBeenNotified: false,
}
}
I am trying to post it to the following node:
updates['jobs/${activeJob.key}/offers/${currentUser.uid}] = offer;
and then firebase.database().ref().update(updates)
As you can see I am using the users uid as the id of the offer itself.
Now when I try to post it using the following rules, I get a permission denied error and I have no clue why.
Rules:
"jobs": {
"$job_uid": {
".read": "auth !== null",
"job": {
".write": "!data.exists() && root.child('allUsers/serviceUsers/' + auth.uid + '/paymentDetails').exists() || data.exists() && root.child('jobs/' + $job_uid + '/job/owner').val() === auth.uid",
},
"offers": {
"$offer_uid": {
"offerInfo": {
".write": "$offer_uid === auth.uid",
},
"offerMetaData": {
".write": "root.child('jobs/' + $job_uid + '/job/owner').val() === auth.uid || $offer_uid === auth.uid",
},
},
},
...
Any ideas?
You are trying to write directly to $offer_uid but you don't have any write rules on that node so it will use the default false.
For you current write to succeed you can change your rules like this:
"$offer_uid": {
".write": "$offer_uid === auth.uid",
"offerMetaData": {
".write": "root.child('jobs/' + $job_uid + '/job/owner').val() === auth.uid",
},
},
I moved the write rule one node up, directly in $offer_uid, instead of having it in both the childs seperatly.
Another option would be to keep your rules and split your write so you are writing to the child nodes.

angular ui-router importing css

I want to load css on demand but I don't get it.
This is the file structure
index.html
<script src="js/ui-router-styles.js"></script>
<script src="js/app.js"></script>
<script src="js/dao.js"></script>
<script src="js/controllers.js"></script>
....
</head>
<body ng-app="starter" ui-router-styles>
<div ui-view></div>
</body>
app.js
var my_app = angular.module('starter', ['starter.posicion_integrada', 'uiRouterStyles','ionic','pascalprecht.translate']);
config part
my_app.config(function($stateProvider, $urlRouterProvider, $ionicConfigProvider) {
$ionicConfigProvider.backButton.previousTitleText(false);
$ionicConfigProvider.backButton.text('');
$stateProvider
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'views/menu.html',
controller: 'appController'
})
.state('app.CarrouselSearcher', {
url: '/CarrouselSearcher/:entUsuario/:codUsuario',
views: {
'menuContent': {
templateUrl: 'views/carrouselSearcher.html',
controller: 'carrouselsearcherCtrl',
data: {
css: ['css/tabla.css', 'css/carousel.css']
}
}
}
})
I found a problem of your code in ui-router-styles.js
is
for(var state = toState; state && state.name !== ''; state=$$parentState(state)) {
if(state && state.data && state.data.css) {
if(!Array.isArray(state.data.css)) {
state.data.css = [state.data.css];
}
angular.forEach(state.data.css, function(css) {
// css = {name: 'layout', href: '/layout.css'}
if(typeof css === 'object' && css.name && css.href && !stylesObject[css.name]) {
stylesObject[css.name] = css.href;
}else if(typeof css === 'string') {
stylesObject[css] = css;
}
});
in your
.state('app.CarrouselSearcher',
your data.css is in another object
state.current.views.menuContent.data.css;
// this condition checks just state.data.css
if(state && state.data && state.data.css) {
your css are in views.menuContent then data.css
so this directive cant finds css from multiple views

Can I created date property if user not send?

I created the rule by using the Firebase Bolt compiler.
// ####### Root
path / {
read() = true;
write() = false;
}
// ######## USERS PHOTOS
// Allow anyone to read the list of Photos.
path /users_photos {
read() = true;
}
// All individual Photos are writable by anyone.
path /users_photos/$id is Photos {
write() = isSignedIn();
}
type Photos {
image: String,
user_id: String,
removed: Boolean,
dt_created: InitialTimestamp,
dt_updated: CurrentTimestamp
}
type CurrentTimestamp extends Number {
validate() = this == now;
}
type InitialTimestamp extends Number {
validate() = initial(this, now);
}
//
// Helper Functions
//
isSignedIn() = auth != null;
// Returns true if the value is intialized to init, or retains it's prior
// value, otherwise.
initial(value, init) = value == (prior(value) == null ? init : prior(value));
Ref: https://github.com/firebase/bolt/blob/master/docs/guide.md
My script:
/*Upload*/
VigiApp.controller('UploadController', ['$scope', 'Upload', '$timeout', 'FirebaseURL', function ($scope, Upload, $timeout, FirebaseURL) {
// upload on file select or drop
$scope.upload = function (file, id) {
$('.page-spinner-bar').removeClass('ng-hide hide').addClass('ng-show show');
id = typeof id !== 'undefined' ? id : null;
Upload.base64DataUrl(file).then(function(base64){
//auth
var fbAuth = FirebaseURL.getAuth();
//Ref
var usersPhotosRef = FirebaseURL.child("users_photos");
usersPhotosRef.push({'image': base64,'removed': true, 'user_id': fbAuth.uid}, function(error){
if (error) {
alert('Error: Something went wrong when creating your post please try again');
} else {
var newID = usersPhotosRef.key();
if(id !== null){
$('#'+id).css("background-image", "url('"+base64+"')");
$('#'+id).css("background-size", "100% 100%");
}
}
$('.page-spinner-bar').removeClass('ng-show show').addClass('ng-hide hide');
});
});
}
}]);
Compile ...
>firebase-bolt mmgv-vigiapp.bolt -o rules.json
bolt: Generating rules.json...
And deploy ...
>firebase deploy:rules
=== Deploying to 'vivid-heat-2144'...
i deploying rules
+ Deploy complete!
Dashboard: https://vivid-heat-2144.firebaseio.com
But I'm getting the error:
FIREBASE WARNING: set at /users_photos/-K5VL1m04oF8s2xp8oTf failed: permission_denied
The rules created:
{
"rules": {
".read": "true",
"users_photos": {
".read": "true",
"$id": {
".validate": "newData.hasChildren(['image', 'user_id', 'removed', 'dt_created', 'dt_updated'])",
"image": {
".validate": "newData.isString()"
},
"user_id": {
".validate": "newData.isString()"
},
"removed": {
".validate": "newData.isBoolean()"
},
"dt_created": {
".validate": "newData.isNumber() && newData.val() == (data.val() == null ? now : data.val())"
},
"dt_updated": {
".validate": "newData.isNumber() && newData.val() == now"
},
"$other": {
".validate": "false"
},
".write": "auth != null"
}
}
}
}
When I remove the date, it works.
...
type Photos {
image: String,
user_id: String,
removed: Boolean,
}
...
How can I generate the creation date and update?
Where is my wrong, please?
When you are adding a Photo, you pass this information:
usersPhotosRef.push({'image': base64,'removed': true, 'user_id': fbAuth.uid}
Your security rules, require these properties:
".validate": "newData.hasChildren(['image', 'user_id', 'removed', 'dt_created', 'dt_updated'])",
There is no magic "default value" for dt_created and dt_updated, so you'll need to pass these in from your application code:
usersPhotosRef.push({
'image': base64,
'removed': true,
'user_id': fbAuth.uid,
'dt_created': Firebase.ServerValue.TIMESTAMP,
'dt_updated': Firebase.ServerValue.TIMESTAMP
}
Since this snippet is adding a new record, dt_created and dt_updated are set to the same value. When you update a record, you'll only want to set dt_updated.

Restricting privileges for anonymous authentication in Firebase with Angular

I am struggling with security rules in Firebase for anonymously authenticated users. I want users to be able to create, read, update, and delete their own projects using anonymous authentication. When I use the code below, Firebase denies permission to the database: Error: permission_denied: Client doesn't have permission to access the desired data.
Does my Angular code need to first create a users folder of some sort in Firebase even though I'm using anonymous authentication?
[EDIT: I've included my routes and some additional code in case it helps.]
Javascript:
myApp.factory('fbAuth', function($firebaseAuth, $firebase) {
var ref = new Firebase('https://xxxxxxxxxx.firebaseio.com');
var authData = ref.getAuth();
if (authData) {console.log('Authenticated user with uid:', authData.uid); } else {
ref.authAnonymously(function (error, authData) {
if (error) {
console.log('Login Failed!', error);
} else {
console.log('Authenticated successfully with payload:', authData);
}
});
}
return authData;
});
myApp.factory('Projects', function($firebase, fbURL) {
return $firebase(new Firebase(fbURL+'/projects')).$asArray();
});
myApp.factory('Selections', function($firebase, fbURL) {
return $firebase(new Firebase(fbURL+'/services')).$asArray();
});
myApp.controller('ProjectListCtrl', function ProjectListCtrl(Projects) {
var projectList = this;
projectList.projects = Projects;
projectList.total = function(){
var total = 0;
angular.forEach(projectList.projects, function(project) {
total += project.type.cost;
});
return total;
};
});
myApp.controller('SelectionListCtrl', function (Selections) {
var selectionList = this;
selectionList.selections = Selections;
this.selectedServices = Selections;
});
Routes:
myApp.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('selection', {
url: '/',
views: {
'list': {
url: '',
templateUrl: 'views/list.html',
controller: 'ProjectListCtrl as projectList',
}
},
'selectionlist': {
templateUrl: 'views/selectionlist.html',
controller: 'SelectionListCtrl as selectionList',
}
})
Security Rules:
{
"rules": {
"projects": {
"$project_id" : {
"$uid": {
".read": "auth != null && auth.uid === $uid",
".write": "auth !=null && auth.uid === $uid" }
}
},
"$other": {".validate": false }
}
}
Firebase Data Structure
Root
- projects
+ -JiVDL4RUSladYTqqHl6
+ -JiVIdH8QIQ8o8q3iKvf
+ -JiYY44i6AOGzTjPDNVM

Resources