nestjs csrf
https://gitissue.com/repos/jiayisheji/blog
pass csrf https://github.com/expressjs/csurf/issues/21
pass csrf https://github.com/expressjs/csurf/issues/21
main.ts
import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path'
import { AppModule } from './app.module';
import * as cookieSession from 'cookie-session';
import * as helmet from 'helmet';
import * as cookieParser from 'cookie-parser';
import * as csurf from 'csurf';
import * as rateLimit from 'express-rate-limit';
async function bootstrap() {
const app = await NestFactory.create(
AppModule,
);
app.init()
app.useStaticAssets(join(__dirname, '..', 'public'));
app.setBaseViewsDir(join(__dirname, '..', 'views'));
app.setViewEngine('pug');
app.set('trust proxy', 1);
app.use(cookieSession({
name: 'session',
keys: ['key1', 'key2']
}));
//app.enableCors();
app.use(helmet());
app.use(cookieParser());
//app.use(csurf({ cookie: true })); //正常是這行,但有些API POST時需要略過csrf
app.use(function (req, res, next) {
var mw = csurf({ cookie: true });
// console.log(req.url) // check real get url
if (req.url === '/testpostcsrf') return next(); //pass csrf check
mw(req, res, next);
});
app.use(
rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
}),
);
await app.listen(3000);
}
bootstrap();
layout.pug
doctype html
html
head
title= title
meta(content= csrfToken, name='csrf-token')
body
block content
login.pug
extends layout
block content
h1 Please log in
if error
p.
#{error}
form(action="/login",method="POST")
input(type="hidden",name="_csrf",value=csrfToken)
input(type="hidden",name="challenge",value=challenge)
table(style="")
tr
td
input(type="email",id="email",name="email",placeholder="email@foobar.com")
td.
(Example: "foo@bar.com")
tr
td
input(type="password",id="password",name="password")
td.
(Example: "foobar")
input(type="checkbox",id="remember",name="remember",value="1")
label(for="remember") Remember me
br
input(type="submit",id="accept",value="Log in")
nest.js 让我们用Nestjs来重写一个CNode
https://gitissue.com/repos/jiayisheji/blog
這網站中的 让我们用Nestjs来重写一个CNode(上、中、下) 幫了大忙,減少大量的浪費時間
===========
html -> jade/pug
http://html2jade.aaron-powell.com/
when you html meta want to become jade/pug
layout.pug
這網站中的 让我们用Nestjs来重写一个CNode(上、中、下) 幫了大忙,減少大量的浪費時間
===========
html -> jade/pug
http://html2jade.aaron-powell.com/
when you html meta want to become jade/pug
layout.pug
meta(content= csrfToken, name='csrf-token')
OpenID hydra docker-compose hydra-login-consent-node mariadb
docker-compose
version: '3.3'
services:
ory-hydra-postgres:
image: postgres:9.6
#restart: always
environment:
- POSTGRES_USER=hydra
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=hydra
volumes:
- hydradata:/var/lib/postgresql/data:rw
networks:
- openid
# 第一次執行postgres要做資料庫格式建立 PS: network依佈屬環境為主 docker network ls 確認
# docker run -it --rm \
# --network openid \
# oryd/hydra:latest \
# migrate sql --yes postgres://hydra:secret@ory-hydra-postgres:5432/hydra?sslmode=disable
ory-hydra:
image: oryd/hydra:latest
restart: unless-stopped
ports:
- "9001:4444"
- "9002:4445"
environment:
- SECRETS_SYSTEM=this_needs_to_be_the_same_a
- DSN=postgres://hydra:secret@ory-hydra-postgres:5432/hydra?sslmode=disable
- URLS_SELF_ISSUER=https://openid.hydra:9001/
- URLS_CONSENT=http://192.168.99.100:9020/consent
- URLS_LOGIN=http://192.168.99.100:9020/login
- LOG_LEVEL=debug
- OAUTH2_EXPOSE_INTERNAL_ERRORS=true
- SERVE_PUBLIC_CORS_ENABLED=true
- SERVE_PUBLIC_CORS_ALLOWED_METHODS=POST,GET,PUT,DELETE
- SERVE_ADMIN_CORS_ENABLED=true
- SERVE_ADMIN_CORS_ALLOWED_METHODS=POST,GET,PUT,DELETE
- SERVE_TLS_KEY_BASE64=LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdVcmdRUUFJZz09Ci0tLS0tRU5EIEVDIFBBUkFNRVRFUlMtLS0tLQotLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUlHa0FnRUJCRENLbkdnVnFJVzdZaW5iUWV5UEd5UTQ0R3U2VVFEelU5SENLYjMzTWlmeFJYRTBkbnU2KzdadQowdEJUcUhQRHVMeWdCd1lGSzRFRUFDS2haQU5pQUFSbng1Nk9jeGNyRWRsYmU4TXRSdUVxWGV2OEREcmh6ZWJGCjM4NlI4Q2RQWDRlUWI2Zll6ekFUL3V3STBsTDdvRmlEWEM3Q0JLWmZUcTdFSzN4TzNXWlpSSjJrMEQ3TnNLd2cKVEpZenJxT0JpczBNeGtva2FUWVVyemhKMXBKY3lmWT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
- SERVE_TLS_CERT_BASE64=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNQVENDQWNLZ0F3SUJBZ0lKQU13RjRiVDRvSnh0TUFvR0NDcUdTTTQ5QkFNQ01Gd3hDekFKQmdOVkJBWVQKQWtGVk1STXdFUVlEVlFRSURBcFRiMjFsTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbgphWFJ6SUZCMGVTQk1kR1F4RlRBVEJnTlZCQU1NREc5d1pXNXBaQzVvZVdSeVlUQWVGdzB4T1RBMk1UY3dNVEl4Ck16ZGFGdzB5T1RBMk1UUXdNVEl4TXpkYU1Gd3hDekFKQmdOVkJBWVRBa0ZWTVJNd0VRWURWUVFJREFwVGIyMWwKTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbmFYUnpJRkIwZVNCTWRHUXhGVEFUQmdOVgpCQU1NREc5d1pXNXBaQzVvZVdSeVlUQjJNQkFHQnlxR1NNNDlBZ0VHQlN1QkJBQWlBMklBQkdmSG5vNXpGeXNSCjJWdDd3eTFHNFNwZDYvd01PdUhONXNYZnpwSHdKMDlmaDVCdnA5alBNQlArN0FqU1V2dWdXSU5jTHNJRXBsOU8KcnNRcmZFN2RabGxFbmFUUVBzMndyQ0JNbGpPdW80R0t6UXpHU2lScE5oU3ZPRW5Xa2x6SjlxTlFNRTR3SFFZRApWUjBPQkJZRUZHK3Z6ZkIxYmVnM1VadEpYRXZWOWRNa1hvNmdNQjhHQTFVZEl3UVlNQmFBRkcrdnpmQjFiZWczClVadEpYRXZWOWRNa1hvNmdNQXdHQTFVZEV3UUZNQU1CQWY4d0NnWUlLb1pJemowRUF3SURhUUF3WmdJeEFMUHYKODZFSFRUVElLcEJHdlQrY2NWN3djSC84SFIrc2xhZC9ZUFhLUlZwd2RDbzUyZVRPV3BDS2dGamtHNEJhd1FJeApBTGxGZFgwbEk2ZzhXS3lhRTVmKzJGZEkxYWVqQ0Ftd0xPTTZTRFJhNFVHbitDa2VwOEljeG1CTDIvQmUzSVZ6CjhnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
networks:
- openid
# 快速建立 auth-doce-client PS: network依佈屬環境為主 docker network ls 確認
#docker run --rm -it \
# -e HYDRA_ADMIN_URL=https://ory-hydra:4445 \
# --network openid \
# oryd/hydra:latest \
# clients create --skip-tls-verify \
# --id auth-code-client \
# --secret secret \
# --grant-types authorization_code,refresh_token \
# --response-types code,id_token,token \
# --scope openid,offline,photos.read \
# --callbacks https://t.tt:9010/callback
ory-hydra-login-consent:
#image: oryd/hydra-login-consent-node:latest
build:
context: hydra-login-consent-node/
restart: unless-stopped
ports:
- "9020:3000"
environment:
- HYDRA_ADMIN_URL=https://ory-hydra:4445
- NODE_TLS_REJECT_UNAUTHORIZED=0
volumes:
- hydraloginconsent:/usr/src/app:rw
depends_on:
- mariadb
networks:
- openid
mariadb:
image: mariadb:10.4.6
#restart: always
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=openid
command: ['--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci']
#第一次使執行db_init_sql.txt
networks:
- openid
adminer:
image: adminer
restart: always
ports:
- 8080:8080
depends_on:
- mariadb
networks:
- openid
volumes:
hydradata:
hydraloginconsent:
networks:
openid:
driver: bridge
Use adminer test maraidb: http://192.168.99.100:8080 root/secret
mariadb init
DROP DATABASE IF EXISTS `openid`;
CREATE DATABASE `openid` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
USE `openid`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` text COLLATE utf8mb4_unicode_ci NOT NULL,
`email` text COLLATE utf8mb4_unicode_ci NOT NULL,
`password` text COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `user` (`id`, `name`, `email`, `password`) VALUES
(1, 'foobar', 'foo@bar.com', '3858f62230ac3c915f300c664312c63f');
ory-hydra-login-consent modify package.json add
"md5": "^2.2.1",
"mysql": "^2.17.1"
ory-hydra-login-consent add db/database.js
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'mariadb',
user : 'root',
password : 'secret',
database: 'openid'
});
var query=function(sql,options,callback){
pool.getConnection(function(err,conn){
pool.query
if(err){
callback(err,null,null);
}else{
conn.query(sql,options,function(err,results,fields){
//释放连接
conn.release();
//事件驱动回调
callback(err,results,fields);
});
}
});
};
module.exports = {query, pool}
ory-hydra-login-consent modify routes/login.js
...
router.post('/', csrfProtection, function (req, res, next) {
// The challenge is now a hidden input field, so let's take it from the request body instead
var challenge = req.body.challenge;
var sql = "select count(*) as count from user where email = ? and password = ?"
var params = [req.body.email, md5(req.body.password)]
//db.get(sql, params, (err, row) => {
pool.query(sql, params, (err, row) => {
if (err) {
res.status(400).json({"db error":err.message});
return;
}
if(!(row.count==1)){ //找不到
res.render('login', {
csrfToken: req.csrfToken(),
challenge: challenge,
error: 'The username / password combination is not correct'
});
return;
}
hydra.acceptLoginRequest(challenge, {
// Subject is an alias for user ID. A subject can be a random string, a UUID, an email address, ....
subject: req.body.email,
// This tells hydra to remember the browser and automatically authenticate the user in future requests. This will
// set the "skip" parameter in the other route to true on subsequent requests!
remember: Boolean(req.body.remember),
// When the session expires, in seconds. Set this to 0 so it will never expire.
remember_for: 3600,
// Sets which "level" (e.g. 2-factor authentication) of authentication the user has. The value is really arbitrary
// and optional. In the context of OpenID Connect, a value of 0 indicates the lowest authorization level.
// acr: '0',
})
.then(function (response) {
// All we need to do now is to redirect the user back to hydra!
res.redirect(response.redirect_to);
})
// This will handle any error that happens when making HTTP calls to hydra
.catch(function (error) {
next(error);
});
});
// Let's check if the user provided valid credentials. Of course, you'd use a database or some third-party service
// for this!
// if (!(req.body.email === 'foo@bar.com' && req.body.password === 'foobar')) {
// // Looks like the user provided invalid credentials, let's show the ui again...
// res.render('login', {
// csrfToken: req.csrfToken(),
// challenge: challenge,
// error: 'The username / password combination is not correct'
// });
// return;
// }
// Seems like the user authenticated! Let's tell hydra...
// hydra.acceptLoginRequest(challenge, {
// // Subject is an alias for user ID. A subject can be a random string, a UUID, an email address, ....
// subject: 'foo@bar.com',
// // This tells hydra to remember the browser and automatically authenticate the user in future requests. This will
// // set the "skip" parameter in the other route to true on subsequent requests!
// remember: Boolean(req.body.remember),
// // When the session expires, in seconds. Set this to 0 so it will never expire.
// remember_for: 3600,
// // Sets which "level" (e.g. 2-factor authentication) of authentication the user has. The value is really arbitrary
// // and optional. In the context of OpenID Connect, a value of 0 indicates the lowest authorization level.
// // acr: '0',
// })
// .then(function (response) {
// // All we need to do now is to redirect the user back to hydra!
// res.redirect(response.redirect_to);
// })
// // This will handle any error that happens when making HTTP calls to hydra
// .catch(function (error) {
// next(error);
// });
// You could also deny the login request which tells hydra that no one authenticated!
// hydra.rejectLoginRequest(challenge, {
// error: 'invalid_request',
// error_description: 'The user did something stupid...'
// })
// .then(function (response) {
// // All we need to do now is to redirect the browser back to hydra!
// res.redirect(response.redirect_to);
// })
// // This will handle any error that happens when making HTTP calls to hydra
// .catch(function (error) {
// next(error);
// });
});
https://t.tt:9010 When login id/pwd, can use adminer change database user email/password.
OpenID hydra docker-compose
docker-compose
version: '3.3'
services:
ory-hydra-postgres:
image: postgres:9.6
#restart: always
environment:
- POSTGRES_USER=hydra
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=hydra
volumes:
- hydradata:/var/lib/postgresql/data:rw
networks:
- openid
# 第一次執行postgres要做資料庫格式建立 PS: network依佈屬環境為主 docker network ls 確認
# docker run -it --rm \
# --network openid \
# oryd/hydra:latest \
# migrate sql --yes postgres://hydra:secret@ory-hydra-postgres:5432/hydra?sslmode=disable
ory-hydra:
image: oryd/hydra:latest
restart: unless-stopped
ports:
- "9001:4444"
- "9002:4445"
environment:
- SECRETS_SYSTEM=this_needs_to_be_the_same_a
- DSN=postgres://hydra:secret@ory-hydra-postgres:5432/hydra?sslmode=disable
- URLS_SELF_ISSUER=https://openid.hydra:9001/
- URLS_CONSENT=http://192.168.99.100:9020/consent
- URLS_LOGIN=http://192.168.99.100:9020/login
- LOG_LEVEL=debug
- OAUTH2_EXPOSE_INTERNAL_ERRORS=true
- SERVE_PUBLIC_CORS_ENABLED=true
- SERVE_PUBLIC_CORS_ALLOWED_METHODS=POST,GET,PUT,DELETE
- SERVE_ADMIN_CORS_ENABLED=true
- SERVE_ADMIN_CORS_ALLOWED_METHODS=POST,GET,PUT,DELETE
- SERVE_TLS_KEY_BASE64=LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdVcmdRUUFJZz09Ci0tLS0tRU5EIEVDIFBBUkFNRVRFUlMtLS0tLQotLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUlHa0FnRUJCRENLbkdnVnFJVzdZaW5iUWV5UEd5UTQ0R3U2VVFEelU5SENLYjMzTWlmeFJYRTBkbnU2KzdadQowdEJUcUhQRHVMeWdCd1lGSzRFRUFDS2haQU5pQUFSbng1Nk9jeGNyRWRsYmU4TXRSdUVxWGV2OEREcmh6ZWJGCjM4NlI4Q2RQWDRlUWI2Zll6ekFUL3V3STBsTDdvRmlEWEM3Q0JLWmZUcTdFSzN4TzNXWlpSSjJrMEQ3TnNLd2cKVEpZenJxT0JpczBNeGtva2FUWVVyemhKMXBKY3lmWT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
- SERVE_TLS_CERT_BASE64=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNQVENDQWNLZ0F3SUJBZ0lKQU13RjRiVDRvSnh0TUFvR0NDcUdTTTQ5QkFNQ01Gd3hDekFKQmdOVkJBWVQKQWtGVk1STXdFUVlEVlFRSURBcFRiMjFsTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbgphWFJ6SUZCMGVTQk1kR1F4RlRBVEJnTlZCQU1NREc5d1pXNXBaQzVvZVdSeVlUQWVGdzB4T1RBMk1UY3dNVEl4Ck16ZGFGdzB5T1RBMk1UUXdNVEl4TXpkYU1Gd3hDekFKQmdOVkJBWVRBa0ZWTVJNd0VRWURWUVFJREFwVGIyMWwKTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbmFYUnpJRkIwZVNCTWRHUXhGVEFUQmdOVgpCQU1NREc5d1pXNXBaQzVvZVdSeVlUQjJNQkFHQnlxR1NNNDlBZ0VHQlN1QkJBQWlBMklBQkdmSG5vNXpGeXNSCjJWdDd3eTFHNFNwZDYvd01PdUhONXNYZnpwSHdKMDlmaDVCdnA5alBNQlArN0FqU1V2dWdXSU5jTHNJRXBsOU8KcnNRcmZFN2RabGxFbmFUUVBzMndyQ0JNbGpPdW80R0t6UXpHU2lScE5oU3ZPRW5Xa2x6SjlxTlFNRTR3SFFZRApWUjBPQkJZRUZHK3Z6ZkIxYmVnM1VadEpYRXZWOWRNa1hvNmdNQjhHQTFVZEl3UVlNQmFBRkcrdnpmQjFiZWczClVadEpYRXZWOWRNa1hvNmdNQXdHQTFVZEV3UUZNQU1CQWY4d0NnWUlLb1pJemowRUF3SURhUUF3WmdJeEFMUHYKODZFSFRUVElLcEJHdlQrY2NWN3djSC84SFIrc2xhZC9ZUFhLUlZwd2RDbzUyZVRPV3BDS2dGamtHNEJhd1FJeApBTGxGZFgwbEk2ZzhXS3lhRTVmKzJGZEkxYWVqQ0Ftd0xPTTZTRFJhNFVHbitDa2VwOEljeG1CTDIvQmUzSVZ6CjhnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
networks:
- openid
#這行非常重要,docker成功運行後,要進geht console執行 admin.addPeer("enode://444a16729d32431bbdaa594272e3509cdeaaf3c995ffb583589163d35f8b36ad14394ab037ac186525f579700e6500cacfb1f953fdf066fa05da0e1d409f7f79@140.110.18.199:30301")
ory-hydra-login-consent:
#image: oryd/hydra-login-consent-node:latest
build:
context: hydra-login-consent-node/
restart: unless-stopped
ports:
- "9020:3000"
environment:
- HYDRA_ADMIN_URL=https://ory-hydra:4445
- NODE_TLS_REJECT_UNAUTHORIZED=0
volumes:
- hydraloginconsent:/usr/src/app:rw
networks:
- openid
# 快速建立 auth-doce-client PS: network依佈屬環境為主 docker network ls 確認
#docker run --rm -it \
# -e HYDRA_ADMIN_URL=https://ory-hydra:4445 \
# --network openid \
# oryd/hydra:latest \
# clients create --skip-tls-verify \
# --id auth-code-client \
# --secret secret \
# --grant-types authorization_code,refresh_token \
# --response-types code,id_token,token \
# --scope openid,offline,photos.read \
# --callbacks https://t.tt:9010/callback
volumes:
hydradata:
hydraloginconsent:
networks:
openid:
driver: bridge
ory-hydra-login-consent download
https://github.com/ory/hydra-login-consent-nodeDirectory name is hydra-login-consent-node
go run main.go
https://sueboy.blogspot.com/2019/06/openid-hydra-cant-finish-error.htmlBroswer https://t.tt:9010
Helm charts for running and operating Hyperledger Fabric in Kubernetes
https://github.com/apggroeifabriek/pivt
hyperledger crypetogen
https://hyperledger-fabric.readthedocs.io/en/release-1.4/commands/cryptogen.html
cryptogen is an utility for generating Hyperledger Fabric key material. It is provided as a means of preconfiguring a network for
cryptogen is an utility for generating Hyperledger Fabric key material. It is provided as a means of preconfiguring a network for
testing purposes
. It would normally not be used in the operation of a production network.Firebase auth and upload image
bootstrap + web firebase realtime + firebase storage
Auth:Use Email&password then input one user with email & password. Login use be added user.
Auth:Use Email&password then input one user with email & password. Login use be added user.
index.html
<!doctype html>
<html lang="zh-Hant-TW">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/4.0.0/firebaseui.css" />
<title>Hello, world!</title>
</head>
<body>
<div class="container">
<div id="firebaseui-auth-container" class="alert alert-light" role="alert"></div>
</div>
<div class="container my-1">
<div class="row">
<div class="col-sm">Login Status
<div class="user-signed-in" style="display: none;"><span class="badge badge-pill badge-success">user-signed-in</span></div>
<div class="user-signed-out" style="display: none;"><span class="badge badge-pill badge-secondary">user-signed-out</span></div>
</div>
<div class="col-sm"><a class="btn btn-outline-primary" data-toggle="collapse" href="#multiCollapseExample1" role="button" aria-expanded="false" aria-controls="multiCollapseExample1">Account Details</a>
<div class="collapse multi-collapse" id="multiCollapseExample1">
<div class="card card-body">
<pre id="account-details">...</pre>
</div>
</div>
</div>
</div>
</div>
<div class="container my-1">
<div class="row justify-content-end">
<div class="col-2">
<div id="sign-in" class="btn btn-outline-primary" style="display: none;">sign-in</div>
<div id="sign-out" class="btn btn-outline-danger" style="display: none;">sign-out</div>
</div>
</div>
</div>
<div class="container my-1">
<div class="row justify-content-center">
<div id="loading" class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
</div>
<div class="container my-1">
<div id="loaded" class="user-signed-in" style="display: none;">檔案上傳
<div id="filesubmit">
<input type="file" class="file-select" accept="image/*"/>
<button class="file-submit">SUBMIT</button>
</div>
</div>
</div>
<div class="container my-1">
<div class="row">
<div class="col-2">
<div id="test" class="btn btn-outline-primary">test</div>
</div>
</div>
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://cdn.firebase.com/libs/firebaseui/4.0.0/firebaseui.js"></script>
<script src="https://www.gstatic.com/firebasejs/ui/4.0.0/firebase-ui-auth__zh_tw.js"></script>
<script defer src="https://www.gstatic.com/firebasejs/6.3.0/firebase-app.js"></script>
<script defer src="https://www.gstatic.com/firebasejs/6.3.0/firebase-auth.js"></script>
<script defer src="https://www.gstatic.com/firebasejs/6.3.0/firebase-database.js"></script>
<!--<script defer src="https://www.gstatic.com/firebasejs/6.3.0/firebase-firestore.js"></script>-->
<script defer src="https://www.gstatic.com/firebasejs/6.3.0/firebase-storage.js"></script>
<script defer src="./init-firebase.js"></script>
<script>
</script>
<script>
document.getElementById('test').addEventListener('click', function() {
var fbdbpath = getfbdbPath('images/@/default/');
putimageurl(fbdbpath, 'url');
});
function fileupload(){ //== File upload ========================
document.querySelector('.file-select').addEventListener('change', handleFileUploadChange);
document.querySelector('.file-submit').addEventListener('click', handleFileUploadSubmit);
let selectedFile;
function handleFileUploadChange(e) {
selectedFile = e.target.files[0];
}
function handleFileUploadSubmit(e) {
var metadata = {
contentType: 'image/jpeg'
};
var fbdbpath = getfbdbPath('images/@/default/');
var newfbdbPostKey= getfbdbPostKey(fbdbpath);
var uploadTask = imagesRef.child(`${newfbdbPostKey}`).put(selectedFile, metadata);
uploadTask.on('state_changed', function(snapshot){
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log('Upload is ' + progress + '% done');
switch (snapshot.state) {
case firebase.storage.TaskState.PAUSED: // or 'paused'
console.log('Upload is paused');
break;
case firebase.storage.TaskState.RUNNING: // or 'running'
console.log('Upload is running');
break;
}
}, function(error) {
// Handle unsuccessful uploads
alert('Upload is Failed;');
console.log(error);
}, function() {
uploadTask.snapshot.ref.getDownloadURL().then(function(downloadURL) {
console.log('File available at', downloadURL);
putimageurl(fbdbpath, downloadURL);
});
}
);
}
}
function initsign(){ //== Auth ===============================
document.getElementById('sign-in').addEventListener('click', function() {
if($('.user-signed-out').css('display') === 'block') ui.start('#firebaseui-auth-container', getUiConfig());
});
document.getElementById('sign-out').addEventListener('click', function() {
var user = firebase.auth().currentUser;
if (user) {
firebase.auth().signOut().then((res)=>{
console.log('signOut ok', res);
}).catch((err)=>{
alert('Logout Failed!');
console.warn('signOut error',res);
}).finally((res)=>{
console.log('signOut resolved', res);
location.reload();
});
}
});
}
</script>
</body>
</html>
init-firebase.js
var firebaseConfig = {
apiKey: 'AIzaSyBxxxxxxooooo',
authDomain: 'product-xxxxxxooooo.firebaseapp.com',
databaseURL: 'https://product-xxxxxxooooo.firebaseio.com',
storageBucket: 'gs://product-xxxxxxooooo.appspot.com'
};
firebase.initializeApp(firebaseConfig);
//== database ===========================
var database = firebase.database();
function getfbdbPath(type){
var userId = firebase.auth().currentUser.uid;
return type.replace("@", userId);
}
function getfbdbPostKey(path){
return firebase.database().ref().child(path).push().key;
}
function putimageurl(path, url){
//var userId = firebase.auth().currentUser.uid;
var path = getfbdbPath('images/@/default/');
var postImg = {
active: true,
url: url,
};
var newPostKey = getfbdbPostKey(path);
var images = {};
images[path + newPostKey] = postImg;
//updates['/user-posts/' + userId + '/' + newPostKey] = postData;
var uploadImagesResult = firebase.database().ref().update(images);
console.log('uploadImagesResult');
console.log(uploadImagesResult);
}
function test(){
var userId = firebase.auth().currentUser.uid;
firebase.database().ref('users/' + userId).set({
username: 'name',
email: 'email',
profile_picture : 'imageUrl'
}, function(error) {
if (error) {
console.log(error)
// The write failed...
} else {
// Data saved successfully!
console.log("successfullly!")
}
});
var c = firebase.database().ref('/users/' + userId).once('value').then(function(snapshot) {
var username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
// ...
console.log("username:", username);
});
console.log('c');
console.log(c);
var postData = {
author: 'username',
uid: userId,
};
var newPostKey = firebase.database().ref().child('posts').push().key;
var updates = {};
updates['/posts/' + newPostKey] = postData;
//updates['/user-posts/' + userId + '/' + newPostKey] = postData;
//firebase.database().ref('posts/' + userId).set(postData);
var t = firebase.database().ref().update(updates);
console.log('t');
console.log(t);
}
//== File upload ========================
var storageRef = firebase.storage().ref();
var imagesRef = storageRef.child('images');
// var otherProject = firebase.initializeApp(firebaseConfig, 'other');
// console.log(otherProject.name); // "otherProject"
// var otherStorage = otherProject.storage();
//== Auth ===============================
function getUiConfig() {
return {
signInSuccessUrl: this.location.href,
signInOptions: [
firebase.auth.EmailAuthProvider.PROVIDER_ID,
],
//immediateFederatedRedirect: false,
};
}
// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());
// The start method will wait until the DOM is loaded.
if (ui.isPendingRedirect()) {
ui.start('#firebaseui-auth-container', getUiConfig());
}
// Disable auto-sign in.
// ui.disableAutoSignIn();
var handleSignedInUser = function(user) {
$('.user-signed-in').show();
$('.user-signed-out').hide();
$('#sign-in').hide();
$('#sign-out').show();
document.getElementById('account-details').textContent = user.displayName;
user.getIdToken().then(function(accessToken) {
document.getElementById('account-details').textContent =
JSON.stringify({
displayName: user.displayName,
email: user.email,
emailVerified: user.emailVerified,
phoneNumber: user.phoneNumber,
photoURL: user.photoURL,
uid: user.uid,
accessToken: user.accessToken,
providerData: user.providerData
}, null, ' ');
});
};
var handleSignedOutUser = function() {
$('.user-signed-in').hide();
$('.user-signed-out').show();
$('#sign-in').show();
$('#sign-out').hide();
//ui.start('#firebaseui-container', getUiConfig());
};
function handleConfigChange() {
// Reset the inline widget so the config changes are reflected.
ui.reset();
ui.start('#firebaseui-container', getUiConfig());
}
firebase.auth().onAuthStateChanged(function(user) {
document.getElementById('loading').style.display = 'none';
document.getElementById('loaded').style.display = 'block';
user ? handleSignedInUser(user) : handleSignedOutUser();
}, function(error) {
console.log(error);
});
initsign();
fileupload();
firebase realtime database rule
95dWpHhg5wOk1loIj0iTneWdfwG2 is admin user <= userId = firebase.auth().currentUser.uid;
{
"rules": {
".read": "'95dWpHhg5wOk1loIj0iTneWdfwG2' === auth.uid",
"users": {
"$uid": {
".write": "$uid === auth.uid"
}
},
"images": {
".write": "'95dWpHhg5wOk1loIj0iTneWdfwG2' === auth.uid",
}
}
}
firebase storage rule
95dWpHhg5wOk1loIj0iTneWdfwG2 is admin user <= userId = firebase.auth().currentUser.uid;
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read;
allow write: if '95dWpHhg5wOk1loIj0iTneWdfwG2' == request.auth.uid;
}
}
}
訂閱:
文章 (Atom)