Skip to content

Commit

Permalink
Merge pull request #4 from hidetak/enable-auth
Browse files Browse the repository at this point in the history
enable basic auth
  • Loading branch information
hidetak authored Mar 12, 2024
2 parents b1fdca6 + 65b3b10 commit ca2a511
Show file tree
Hide file tree
Showing 15 changed files with 226 additions and 89 deletions.
9 changes: 9 additions & 0 deletions node-red-node-wot/src/locales/en-US/wot-thing-config.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ <h3>Details</h3>
to this setting are published with the Thing title specified here.
</li>
<li>Description: Specify the description of the Thing.</li>
<li>
Thing ID: Specify the Thing ID. The specified Thing ID is used as the ID for Thing Description.
If omitted, the ID for Thing Description is automatically generated.<br/>
Example of Thing ID: "urn:dev:ops:32473-WoTLamp-1234"
</li>
<li>
Use basic authentication: Specifies whether Basic authentication is applied to the Thing.<br/>
If you use Basic Authentication, please set your user name and password.
</li>
</ul>
<p>
The Thing Description is stored in the thingDescriptions variable of the global context with the key of
Expand Down
7 changes: 6 additions & 1 deletion node-red-node-wot/src/locales/en-US/wot-thing-config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
{
"editor": {
"nameLabel": "Thing title",
"descriptionLabel": "Description"
"descriptionLabel": "Description",
"thingIdLabel": "Thing ID",
"securityLabel": "Security:",
"basicAuthLabel": "Use basic authentication",
"usernameLabel": "Username",
"passwordLabel": "Password"
}
}
9 changes: 9 additions & 0 deletions node-red-node-wot/src/locales/ja/wot-thing-config.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ <h3>Details</h3>
Descriptionでは、ここで指定したThing名で、本設定を参照するプロパティ、アクション、イベントを公開します。
</li>
<li>説明: Thingの説明を指定します。</li>
<li>
Thing ID: Thing IDを指定します。指定したThing IDは、Thing
DescriptionのIDとして利用します。省略した場合は、Thing DescriptionのIDは自動的に生成されます。<br/>
Thing IDの例: "urn:dev:ops:32473-WoTLamp-1234"
</li>
<li>
Basic認証利用: ThingにBasic認証をかけるかどうかを指定します。<br/>
Basic認証を利用する場合は、ユーザー名とパスワードを設定してください。
</li>
</ul>
<p>
Thing
Expand Down
7 changes: 6 additions & 1 deletion node-red-node-wot/src/locales/ja/wot-thing-config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
{
"editor": {
"nameLabel": "Thing名",
"descriptionLabel": "説明"
"descriptionLabel": "説明",
"thingIdLabel": "Thing ID",
"securityLabel": "セキュリティ:",
"basicAuthLabel": "Basic認証利用",
"usernameLabel": "ユーザー名",
"passwordLabel": "パスワード"
}
}
6 changes: 6 additions & 0 deletions node-red-node-wot/src/servients/servient-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ export default class ServientWrapper {
return this.things[thingName]
}

public addCredentials(title, credentials) {
const thing = this.things[title]
const td = thing.getThingDescription()
this.servient.addCredentials({ [td.id]: credentials })
}

public async endServient() {
if (this.server) {
console.debug("[debug] endServient called.")
Expand Down
39 changes: 21 additions & 18 deletions node-red-node-wot/src/wot-event.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = function (RED) {
let node = this
let consumedThing
let subscription
let repeatId

this.status({})

Expand All @@ -19,15 +20,20 @@ module.exports = function (RED) {

const thingNode = RED.nodes.getNode(config.thing)
thingNode.addUpdateTDListener(async (_consumedThing) => {
if (repeatId) {
clearInterval(repeatId)
repeatId = undefined
}
if (subscription) {
// Stop if already subscribed
await subscription.stop()
}
subscription = undefined
consumedThing = _consumedThing
// Repeat until event subscription succeeds.
try {
while (true) {
subscription = await consumedThing
await new Promise((resolve, reject) => {
repeatId = setInterval(() => {
consumedThing
.subscribeEvent(
config.event,
async (resp) => {
Expand Down Expand Up @@ -63,24 +69,17 @@ module.exports = function (RED) {
subscription = undefined
}
)
.then((sub) => {
subscription = sub
clearInterval(repeatId)
repeatId = undefined
resolve()
})
.catch((err) => {
console.warn("[warn] event subscribe error. try again. error: " + err)
})
if (subscription) {
break
}
await new Promise((resolve) => {
setTimeout(resolve, 500)
})
}
} catch (err) {
node.status({
fill: "red",
shape: "ring",
text: "Subscription error",
})
node.error(`[error] failed to subscribe events. error: ${err.toString()}`)
}
}, 1000)
})

if (subscription) {
node.status({
Expand All @@ -92,6 +91,10 @@ module.exports = function (RED) {
})

this.on("close", async function (removed, done) {
if (repeatId) {
clearInterval(repeatId)
repeatId = undefined
}
if (subscription) {
// Stop if already subscribed
await subscription.stop()
Expand Down
92 changes: 51 additions & 41 deletions node-red-node-wot/src/wot-property.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = function (RED) {
let node = this
let consumedThing
let subscription
let repeatId

this.status({})

Expand All @@ -23,62 +24,67 @@ module.exports = function (RED) {

const thingNode = RED.nodes.getNode(config.thing)
thingNode.addUpdateTDListener(async (_consumedThing) => {
if (repeatId) {
clearInterval(repeatId)
repeatId = undefined
}
if (subscription) {
// Stop if already subscribed
await subscription.stop()
}
subscription = undefined
consumedThing = _consumedThing
if (config.observe === false) {
return
}
// Repeat until observeProperty succeeds.
while (true) {
try {
subscription = await consumedThing.observeProperty(
config.property,
async (resp) => {
let payload
try {
payload = await resp.value()
} catch (err) {
node.error(`[error] failed to get property change. err: ${err.toString()}`)
console.error(`[error] failed to get property change. err:`, err)
await new Promise((resolve, reject) => {
repeatId = setInterval(() => {
consumedThing
.observeProperty(
config.property,
async (resp) => {
let payload
try {
payload = await resp.value()
} catch (err) {
node.error(`[error] failed to get property change. err: ${err.toString()}`)
console.error(`[error] failed to get property change. err:`, err)
}
node.send({ payload, topic: config.topic })
},
(err) => {
node.error(`[error] property observe error. error: ${err.toString()}`)
console.error(`[error] property observe error. error: `, err)
node.status({
fill: "red",
shape: "ring",
text: "Observe error",
})
}
node.send({ payload, topic: config.topic })
},
(err) => {
node.error(`[error] property observe error. error: ${err.toString()}`)
console.error(`[error] property observe error. error: `, err)
)
.then((sub) => {
subscription = sub
clearInterval(repeatId)
repeatId = undefined
resolve()
})
.catch((err) => {
console.warn("[warn] property observe error. try again. error: " + err)
node.status({
fill: "red",
shape: "ring",
text: "Observe error",
})
}
)
} catch (err) {
console.warn("[warn] property observe error. try again. error: " + err)
node.status({
fill: "red",
shape: "ring",
text: "Observe error",
})
}
if (subscription) {
node.status({
fill: "green",
shape: "dot",
text: "connected",
})
break
}
await (() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve()
}, 500)
})
})()
})
}, 1000)
})
if (subscription) {
node.status({
fill: "green",
shape: "dot",
text: "connected",
})
}
})

Expand Down Expand Up @@ -119,6 +125,10 @@ module.exports = function (RED) {
})

node.on("close", async function (removed, done) {
if (repeatId) {
clearInterval(repeatId)
repeatId = undefined
}
if (subscription) {
// Stop if already subscribed
await subscription.stop()
Expand Down
5 changes: 2 additions & 3 deletions node-red-node-wot/src/wot-server-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ module.exports = function (RED) {
}

// for wot-server-config
node.getThingProps = () => {
const woTThingConfig = RED.nodes.getNode(config.woTThingConfig)
return woTThingConfig.getProps()
node.getThingNode = () => {
return RED.nodes.getNode(config.woTThingConfig)
}

node.on("close", function (removed, done) {
Expand Down
67 changes: 54 additions & 13 deletions node-red-node-wot/src/wot-server-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ module.exports = function (RED) {
}
}

function getSecurityDefinition(scheme) {
let params
if (scheme === "basic") {
params = { scheme, in: "header" }
} else {
params = { scheme }
}
return params
}

async function waitForFinishPrepareRelatedNodes(userNodes: any[], userNodeIds: string[]) {
const MAX_CHECK_COUNT = 50
const WAIT_MILLI_SEC = 100 //ms
Expand Down Expand Up @@ -118,7 +128,13 @@ module.exports = function (RED) {
}

async function createWoTScriptAndExpose(
thingProps: { title: string; description: string },
thingProps: {
title: string
description: string
id?: string
securityDefinitions?: any
security?: string[]
},
servientWrapper: ServientWrapper,
userNodes: any[]
) {
Expand Down Expand Up @@ -156,7 +172,6 @@ module.exports = function (RED) {
}

async function launchServient() {
node.bindingType = node.credentials.bindingType
if (config.bindingConfigConstValue && config.bindingConfigType) {
node.bindingConfig = RED.util.evaluateNodeProperty(
config.bindingConfigConstValue,
Expand All @@ -168,27 +183,53 @@ module.exports = function (RED) {
// create thing
const bindingType = config.bindingType
const bindingConfig = node.bindingConfig
console.debug("[debug] createServient ", node.id, bindingType, bindingConfig)
const servientWrapper = servientManager.createServientWrapper(node.id, bindingType, bindingConfig)
try {
await waitForFinishPrepareRelatedNodes(userNodes, config._users)
await servientWrapper.startServient()
// make thing title list
const thingNamesObj = {}
// make thing title list and security definitions
const securityDefinitions = []
const thingTitles = []
for (const userNode of userNodes) {
if (userNode.type === "wot-server-td") {
continue
}
thingNamesObj[userNode.getThingProps().title] = true
let thingNode = userNode.getThingNode()
if (!thingNode) {
continue
}
let title = thingNode.getProps()?.title
if (title && !thingTitles.includes(title)) {
thingTitles.push(title)
// make security definitions for server
let secDef = getSecurityDefinition(thingNode.getSecurityScheme())
if (secDef.scheme !== "nosec") {
securityDefinitions.push(secDef)
}
}
}
const thingNames = Object.keys(thingNamesObj)
// merge security params to bindingConfig
bindingConfig["security"] = securityDefinitions
console.debug("[debug] createServient ", node.id, bindingType, bindingConfig)
const servientWrapper = servientManager.createServientWrapper(node.id, bindingType, bindingConfig)
await servientWrapper.startServient()
// Generate and Expose a Thing for each Thing title
for (const thingName of thingNames) {
for (const thingTitle of thingTitles) {
const targetNodes = userNodes.filter(
(n) => n.type !== "wot-server-td" && n.getThingProps().title === thingName
(n) => n.type !== "wot-server-td" && n.getThingNode().getProps().title === thingTitle
)
const thingProps = targetNodes[0]?.getThingProps() || {}
await createWoTScriptAndExpose(thingProps, servientWrapper, targetNodes)
if (targetNodes.length > 0) {
const thingNode = targetNodes[0].getThingNode()
const thingProps = thingNode.getProps() || {}
// add security definition to thingProps
const secScheme = thingNode.getSecurityScheme()
if (secScheme !== "nosec") {
thingProps["securityDefinitions"] = {
sc: getSecurityDefinition(secScheme),
}
thingProps["security"] = ["sc"]
}
await createWoTScriptAndExpose(thingProps, servientWrapper, targetNodes)
servientWrapper.addCredentials(thingProps.title, thingNode.getCredentials())
}
}
node.running = true
userNodes.forEach((n) => {
Expand Down
Loading

0 comments on commit ca2a511

Please sign in to comment.