README
How to install and develop Account plugin
This is all about how to develop this next-dapp account plugin, not how to develop a next-dapp based project itself.
Next Dapp itself is based upon Next.js / React and heavily powered by Recoil state management library. Other major dependencies are Ramda and Rebass.
The core plugin is located at @nextdapp/core.
A working example can be found here.
You will need the nextdapp command line tool for development. Install it globally with npm
or yarn
.
I will use yarn
throughout this document.
sudo npm i -g nextdapp
or
yarn global add nextdapp
1. Clone the repo & Install node modules
A demo directory is nested inside the plugin directory. They are separate projects, so you need to install the required packages for the both projects separately.
# clone
git clone https://github.com/warashibe/nd-account.git
# move to the plugin dixrectory and install node modules with yarn
cd nd-account && yarn
# move to the demo directory and install node modules with yarn
cd demo && yarn
2. Copy and Modify conf.sample.js file
nd/conf.js
is ignored by .gitignore
, so you need to copy nd/conf.sample.js
to nd/conf.js
and modify it according to your needs. For now, keep all the dummy data even if you don't use some login methods. The plugin throws an error, if something is missing. This behavior will be taken care of in the future.
cp nd/conf.sample.js nd/conf.js
Sample Settings [/nd/conf.js]
import { mergeAll } from "ramda"
let local = {}
try {
local = require("nd/conf.local")
} catch (e) {}
const prod = {
id: "next-dapp",
html: {
title: "Next Dapp | The Bridge between Web 2.0 and 3.0",
description:
"Next Dapp is a web framework to progressively connect web 2.0 with 3.0.",
image: "https://picsum.photos/1000/500",
"theme-color": "#03414D"
},
firebase: {
name: "xxx-xxx",
id: "xxx-xxx",
key: "xxxxxxx",
sender: "123456789",
region: "us-central1"
},
web3: {
network: "3" // Ropsten Testnet
},
alis: {
client_id: "123456789,
redirect_uri: "http://localhost:3000/"
},
steem: {
redirect_uri: "http://localhost:3000/",
app: "ocrybit"
},
uport: {
name_field: "氏名又は名称",
id_field: "交付番号",
appName: "暗号資産古物商協会",
did: "did:ethr:0x62507aa089182659ff595266e3c1de2975a51780",
verified: "古物商許可証テストネット"
}
}
module.exports = mergeAll([prod, local])
4. Setup credentials as env values
Sensitive data such as private keys are not to be mixed with the configurations above, use .env
for credintials.
touch .env
replace below with your data [/.env]
UPort requires my private key and not configurable for anyone other than me at the moment.
# if not used, you don't need alis and uport credentials
ALIS_CLIENT_SECRET=xxxxxxxxx
UPORT_PRIVATE_KEY=xxxxxxxx
WEB3_INFURA=https://ropsten.infura.io/v3/xxxxxxx
UPORT_RPCURL=https://mainnet.infura.io/v3/xxxxxxxx
5. Setup Firestore and Cloud Functions
Initialize firebase project (choose Firestore and Functions)
Create a new project if you don't have one to use for the development. Do not overwrite any files during the initialization such as firebase/firestore.rules
. If you keep pressing Enter
without changing the default options, you won't overwrite anything.
Alternatively, create one from the web console https://console.firebase.google.com. Then run below.
You need to set a cloud resource location by setting up Firestore
via the web console above.
You need to install firebase-tools
and set it up first. Refer to this page.
npm install -g firebase-tools
Once you set it up and log in, proceed.
cd firebase && firebase init
How to set up login methods
- Google, Twitter, Github, Facebook can be set up via Firebse console.
- ALIS: Register an OAuth app from here, and set the redirect URI to
http://localhost:3000/
. - STEEM: Set up steemconnect somehow... I forgot how :)
- Metamask, Authereum: You will need the
@nextdapp/web3
plugin to make it work. - UPort: It only works with my private key at the moment, to be extended.
update security rules for Firestore
firebase deploy --only firestore:rules
create env.json and deploy environmental variables and functions
Functions are only compatible with node v.10.x. Use nvm
to temporarily switch versions.
nvm
can be installed by yarn
or npm
yarn global add nvm
Create /firebase/functions/env.json
and modify as shown below. If you are not using the web3 based login methos, just copy and paste below for dummy data.
cd functions && nvm use 10 && yarn && touch env.json
/firebase/functions/env.json
{
"web3": {
"infura": "https://ropsten.infura.io/v3/xxxxx"
},
"uport": {
"name_field": "氏名又は名称",
"id_field": "交付番号",
"appName": "暗号資産古物商協会",
"did": "did:ethr:0x62507aa089182659ff595266e3c1de2975a51780",
"privateKey":
"xxxxxxx",
"rpcUrl": "https://mainnet.infura.io/v3/xxxxx",
"verified": "古物商許可証テストネット"
}
}
Upload env to your remote Cloud Functions environment. This command will do the magic.
firebase functions:config:set env="$(cat env.json)"
Deploy functions.
cd ..
firebase deploy --only functions
6. Run the demo locally
cd ../demo
yarn dev
Adding a New Login Method
1. add login mehtod data to const.js
/src/const.js
Example: url
is optional.
{
key: "alis",
name: "ALIS",
bg: "#232538",
url: v => `https://alis.to/users/${v.username}`
}
/static/images directory
2. add two types of icons toName them github-white.png
(Login Button) and github.png
(Link to User Account).
const login_with
in /src/account.js
3. add a function to Example
This will redirect the user to alis.to for an OAuth2.0 authentication flow.
You automatically get { set, values, conf }
as the arguments.
alis: async ({ conf }) => {
const code_verifier = get_code_verifier()
const code_challenge = get_code_challenge(code_verifier)
const purl = `https://alis.to/oauth-authenticate?client_id=${
conf.alis.client_id
}&redirect_uri=${encodeURIComponent(
conf.alis.redirect_uri
)}&scope=write&code_challenge=${code_challenge}`
setCookie(null, "alis_verifier", code_verifier, { path: "/" })
window.location.href = purl
},
4. add a callback function to execute after redirecting back from OAuth provider (if needed)
Next-Dapp utilizes Recoil - the Facebook official state management library.
If you change global states, you need to list them in the first argument like done below -["processing$util"]
.
set
can change globally reactive states in this way.
If you need your own global states, define them in /src/init.js, and add them to /nextdapp.json. If you define your_state
, it will namespaced and become your_state$account
throughout the app.
Example
export const check_alis = [
["processing$util"],
async ({ val: { router }, state$, set }) => {
const code = router.query.code
if (isNil(code)) return
set(true, "processing$util")
const cookies = parseCookies()
const alis_verifier = cookies.alis_verifier
let user = await checkUser(state$)
let login_url = `/api/alis-oauth_account?code=${code}&verifier=${
cookies.alis_verifier
}`
await _login_with({ login_url, set, state$, provider: "alis" })
router.replace(router.pathname, router.pathname, { shallow: true })
}
]
const name_map
and link_converter
5. set a user data converter via Example
Pick necessary fields to form a user data from add
.
name
, image
and description
are preffered to be assigned.
const name_map = {
"alis.to": "alis",
const link_converter = {
"alis.to": (_u, add) =>
mergeLeft(
{
name: add.user_display_name,
image: add.icon_image_url,
description: add.self_introduction,
username: add.user_id
},
_u
),
6. bind and execute the callback function when the required query parameter exists in the demo.
Plugin functions will be automatically namespaced. check_alis
becomes fn.check_alis$account
.
Example: /demo/page/index.js
useEffect(
() => {
if (hasPath(["router", "query", "code"])(props)) {
isFirebase(props.conf).then(() => {
fn.check_alis$account({ router: props.router })
})
}
},
[props.router.query]
)
Don't forget to bind the function to the Component.
[
"user$account",
"uport$account",
"processing$util",
"changeUser$account",
"check_alis$account", // <= bind to Component
"linkAccount$account",
"unlinkAccount$account"
]
Next.js api or/and Cloud Functions.
7. write the logic to generate custom_token usingFor alis, refer to /src/api/alis-oauth.js and exports login
in /firebase/functions/index.js.
If you need any credentials to set for Cloud Functions, refer back to create env.json and deploy environmental variables and functions
Public configurations for Next.js app can be set as described in 2. Copy and Modify conf.sample.js file
Credentials for Next.js app can be set as described in 4. Setup credentials as env values
/nextdapp.js
8. if you have added public apis, cloud functions or env variables, specify them in {
"epics": [ "changeUser", "logout", "logout_authereum", "login", "check_alis", "deleteAccount", "linkAccount", "unlinkAccount" ],
"props": [ "user", "user_init", "uport", "_user" ],
"api": { "apiAlisOauth": "alis-oauth", "apiSteemOauth": "steem-oauth", "apiUportLogin": "uport-login" },
"functions": { "nd-account-functions": [ "loginUport", "loginMetamask", "loginAuthereum", "login" ] },
"env": [ "ALIS_CLIENT_SECRET", "UPORT_PRIVATE_KEY", "WEB3_INFURA", "UPORT_RPCURL" ],
"components": ["Login", "UPort", "Profile", "LinkAccount"]
}
9. build pulugin, update package and deploy functions
build plugin
yarn build
@nextdapp/account
package
move to demo directory and update Use .. noinstall
for local rebuild and update. It will link to the updated local file without installing the node package.
You don't need them when updating directly from node package registry
.
cd demo
nextdapp remove @nextdapp/account .. noinstall
nextdapp add @nextdapp/account .. noinstall