I'm using this code to play around with IPFS in the browser. I'm wondering how I can access the ip addresses of the webRTC peers? or even know if the peers are actually webRTC, or http peers?
<script src="https://cdn.jsdelivr.net/npm/ipfs/dist/index.min.js"></script>
<script>
(async () => {
window.node = await Ipfs.create({
config: {
Addresses: {
Swarm: []
},
Bootstrap: []
}
})
window.node.libp2p.on('peer:discovery', (peer) => console.log('peer:discovery', peer))
window.node.libp2p.on('peer:connect', peerInfo => console.log('peer:connect', peerInfo))
window.node.libp2p.on('peer:disconnect', peerInfo => console.log('peer:disconnect', peerInfo))
window.node.libp2p.peerStore.on('peer', (peerId) => console.log('peer', peerId))
window.node.libp2p.peerStore.on('change:multiaddrs', ({ peerId, multiaddrs}) => console.log('change:multiaddrs', {peerId, multiaddrs}))
window.node.libp2p.peerStore.on('change:protocols', ({ peerId, protocols}) => console.log('change:protocols', {peerId, protocols}))
window.node.libp2p.on('error', (err) => console.log('error', err))
window.node.libp2p.connectionManager.on('peer:connect', (connection) => console.log('peer:connect', connection))
window.node.libp2p.connectionManager.on('peer:disconnect', (connection) => console.log('peer:disconnect', connection))
const data = 'Hello'
const results = await window.node.add(data)
console.log({results})
})()
</script>
node.swarm.peers() gives me a list of peers, but it doesn't seem to include the IP address.
Looking at your config, it seems that you did not configure any swarm address. A swarm address must be configured for your peer to be diable from other peers in the network.
Some context, in this specific case, you are dealing with a browser environment. Currently, Browsers do not allow listening for connections. One of the limitations is actually that a browser does not provide an "IP Address" that someone can use to reach to it. They are designed in a client-server model where the server IP Address is known and the client will establish the connection with it.
As one of the ways to solve the issue above, there is libp2p-webrtc-star transport. It basically uses a server that will be responsible for listening for connections on behalf of browser nodes. You can use one of the available servers for experimenting https://github.com/libp2p/js-libp2p-webrtc-star#hosted-rendezvous-server. Basically, you should add to your swarm addresses, a multiaddr such as /dns4/wrtc-star1.par.dwebops.pub/tcp/443/wss/p2p-webrtc-star. Once your node starts, your browser node will establish a connection with the server and the server will inform all the other peers about the peer who joined. These peers can dial your peer via this star server and the multiaddrs will look something like: /dns4/wrtc-star1.par.dwebops.pub/tcp/443/wss/p2p-webrtc-star/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM.
With this setup, you should be able to open multiple browsers and peers discover and connect to each other. If you run the ipfs.swarm.peers you should see the addresses of the other nodes peers via the star server.
I hope this helps you move forward. I also highly recommend you to check the following examples:
https://github.com/ipfs/js-ipfs/tree/master/examples/browser-exchange-files
https://github.com/libp2p/js-libp2p/blob/master/examples/libp2p-in-the-browser
As a complement, there are a few new features being worked on that aim to improve the browser experience in this regard. You can follow the developments on: https://github.com/libp2p/js-libp2p/issues/703
Related
I have an app which interacts with the database directly with mysql1 library like the example below:
Future FetchData() async {
final connection = await MySqlConnection.connect(ConnectionSettings(
host: 'mysql-hostname.example.com',
port: 3306,
user: 'root',
password: 'root',
db: 'testDB',
));
var results = await connection.query('SELECT * FROM `testTable` WHERE 1');
for (var row in results) {
print('${row[0]}');
}
// Finally, close the connection
await connection.close();
}
I wonder if this is a safe and secure method. Because when I build the app I pack all the information (username, password) about connecting my database in the app. Is this risky so should I use a separate back-end for this kind of tasks?
It is generally safer to put a trusted backend environment between your database and app. But even in this case you will have to ensure that only your app has access to this backend resource.
For example if you use Firebase as backend, there is an AppCheck service available. Although this is relatively new, it can attest your app's authenticity.
If you prefer to do it on your own, you can create a bearer token that your app will add the the requests, preferably in the request's Authorization header, and check it in the backend before accessing protected resources. But then the question remains, where do you store this bearer token safely.
If you want to keep it in your code, you should properly obfuscate the code before uploading it to the app stores. Even in this case it is a good idea to check for rooted or jailbroken devices to prevent misuse, for example check out flutter_jailbreak_detection.
There are also secure storage packages, which can store sensitive data in a safer way. Unlike SharedPreferences, these can mitigate the risks of unauthorited access to your secrets. See flutter_secure_storage for example.
It really depends on the level of security that you are looking for. Are you storing user-generated sensitive information in your database? Then the answer is that you should ideally not store that information in your code nor should you ship your application with that information bundled inside it.
I highly suggest that you start using Firebase for your usage. Firebase is an absolutely fantastic and free product provided by the Google, the same company behind Flutter, and within a few minutes you can build a whole experience that relies on authentication with Firebase and you can safely store user-generated content in Firebase.
My apologies if this is a duplicate. I can find a million results about CORS policy issues, but not about this specific one:
I developed a simple "speed test" site for my users (wfh employees of my company) to access. It tests speeds across the public net to different datacenters we utilize, and via the users' VPN connection to one of our DCs.
There are more complicated elements, but for a basic round-trip "ping" I have an extremely simple PHP script on the server that contains:
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: *');
if ($_GET['simple'] == '1')
die('{ }');
?>
It is called like this:
$.ajax({
type: 'GET',
url: sURL,
data: { ignore: (pingCounter.start = new Date().getTime()) },
dataType: 'text',
timeout: iTimeout
})
.done(function(ret) {
pingCounter.end = new Date().getTime();
[...] (additional code omitted for brevity)
(I know this has additional overhead other than the raw round-trip network traffic timing, but I don't need sub-ms accuracy. I just need to be able to tell users "the problem is on your end" or "ah yes, the problem is the latency between your house and this particular DC".)
The same server running that PHP code is addressable at the following URLs at the DC wherein our VPN server lies:
http://speedtest-int.mycompany.com/ping.php
http://speedtest-ext.mycompany.com/ping.php
Public DNS resolves like this:
speedtest-int.mycompany.com IN A 1.1.1.1 (Actual public IP redacted)
speedtest-int.mycompany.com IN A 10.1.1.1 (Actual internal IP redacted)
If I access either URL from my browser directly, it loads fine (which is to say it responds with { }).
When loading via the JS snippet above, the call to http://speedtest-ext.mycompany.com/ping.php works fine.
The call to http://speedtest-int.mycompany.com/ping.php fails with "The request client is not a secure context and the resource is in more-private address space 'private'".
Fair enough, the solution is to add Access-Control-Allow-Private-Network: *, right?
EXCEPT that apparently can only be used with SSL:
https://developer.chrome.com/blog/private-network-access-update/
I have a self-signed cert on there, but that obviously fails by policy for that reason.
I could just get a LetsEncrypt cert for multiple subdomains. EXCEPT it will never validate the URL http://speedtest-int.mycompany.com because the LetsEncrypt servers won't be able to reach that to validate ownership, as it's a private IP.
I have no control over most of my users' machines, so I can't necessarily install trusted internal certs or change browser options. Most users use Chrome.
So is my solution to buy a UCC or wildcard cert?
I feel like I'm in a catch-22, and I don't want to spend however-much on a UCC cert for an internal app that will be very very very occasionally used by one of our 25 home-based employees when I want to prove that their home "internet is bad" and not the corp network.
Thanks in advance; I'm sure there's a stupidly obvious solution I'm not seeing.
(I'm considering pushing a /32 route to my VPN users for another real public IP to be used in place of the internal IP. Then I can have the "internal" test run against an otherwise publicly accessible IP which could be validated by LetsEncrypt, but VPN users would hit it via the VPN. Is that silly?)
Edit: If anyone is curious -- or it helps to clarify my goal here -- this is the output when accessing the speedtest page:
http://s.co.tt/wp-content/uploads/2021/12/Internal_Speedtest_Example-Redacted.png
It repeats for 20 cycles (or until stopped) and runs each element a varying number of times per cycle, collecting the average time for each. It ain't pretty, but it work(ed).
I did a test to see what would happen if I try getting a CID that doesn't exist, to see if I could continuously ask every peer in IPFS. It doesn't seem to work. I "connect" to around 10 peers, then it gives up. I'm not sure I'm actually "connecting" though. I'm not really sure what going on. I don't know that I'm actually connecting to any peer and asking them for a CID. I seem to connect to a star server, and see a list a peer, but not sure I ever connect to any of those peers.
Are there other events I should be listening to to debug what's going on? How can I listen to the messages I'm sending to peers?
My assumption from how Bittorrent DHT works is that, if a CID doesn't exist, I should eventually be asking every single peer on the network if they have this CID. Is there only 10 peers in the entire network? Or only 10 peers on that star server? Is there no star server discovery? How do I find a "busy" star server?
<script src="https://cdn.jsdelivr.net/npm/ipfs/dist/index.min.js"></script>
<script>
(async () => {
window.node = await Ipfs.create()
window.node.libp2p.on('peer:discovery', (peer) => console.log('peer:discovery', peer))
window.node.libp2p.on('peer:connect', peerInfo => console.log('peer:connect', peerInfo))
window.node.libp2p.on('peer:disconnect', peerInfo => console.log('peer:disconnect', peerInfo))
window.node.libp2p.peerStore.on('peer', (peerId) => console.log('peer', peerId))
window.node.libp2p.peerStore.on('change:multiaddrs', ({ peerId, multiaddrs}) => {
const addresses = []
for (const multiaddr of multiaddrs) {
addresses.push(multiaddr.buffer.toString())
}
console.log('change:multiaddrs', {peerId, multiaddrs, addresses})
})
window.node.libp2p.peerStore.on('change:protocols', ({ peerId, protocols}) => console.log('change:protocols', {peerId, protocols}))
window.node.libp2p.on('error', (err) => console.log('error', err))
window.node.libp2p.connectionManager.on('peer:connect', (connection) => {
console.log('connectionManager:peer:connect', {connection, remoteAddr: connection.remoteAddr.buffer.toString()})
})
window.node.libp2p.connectionManager.on('peer:disconnect', (connection) => console.log('connectionManager:peer:disconnect', connection))
// fake CID does not exist
results = window.node.get("QmZbj5ruYneZb8FuR9wnLuJCpCXMQudhSdWhdhp5U1oPWJ")
for await (res of results) {
for await (content of res.content) {
window.content = content
console.log(content.toString())
}
}
})()
</script>
js-ipfs does not have the DHT enabled by default at this moment. You need to explicitly enable it through the create options. That would result in the IPFS bitswap protocol to query the network for the content you are looking for. During the DHT query, as you also described, the peer will connect to other peers on the network according to the DHT algorithm, in order to find the content.
So, why do we have the DHT disabled by default? The JS DHT implementation was not scaling well for several reasons, some related to the DHT implementation itself and others like undiable nodes in the network and a not efficient connection manager. GO DHT was really improved a few months ago and the JS implementation will be completely refactored according to the recent changes in the GO implementation. The connection manager improvements are also on the way.
While the DHT is not refactored and stable, it is recommended to leverage delegate nodes. A delegate node is a node that will make content and peer routing queries on behalf of others. js-ipfs#0.48 was released with some public delegated nodes configured by default. The delegate nodes are GO nodes that will do the DHT queries on behalf of the JS nodes, this way, it will be the go node behind the scenes that will establish the connections with other nodes.
Let me know if I could answer your issue
We have a hard time understanding the meaning of the different hierarchy levels provided by the iotagent. There is the fiware-service, the fiware-servicepath and underneath it is a bunch of services that in turn have a bunch of devices associated.
Now we understood how to query for all devices and all services underneath a given fiware-service and fiware-servicepath. We also understood how to query for all fiware-servicepaths given a certain fiware-service. But how to query for all those "top level" fiware-services?
Our goal is to create a device management user interface which enables an end user to provision and unprovision the devices he is managing. Maybe we have a misconception of the fiware-service here but since one can add such services with a certain POST request our expectation would be that we can somehow query for all those services. What are we missing?
If there really is no way to query the top level services, I'd like to ask for the reasoning of this as I cannot find that in the docs.
Under NGSI-v2, all context brokers are implicitly multitenant. Using a different fiware-service for your provisioned devices should imply that the devices and their data are owned by separate business concern, so there should be no need to retrieve and combine provisioned devices from separated concerns.
When using the mongo-DB option with an IoT Agent, the fiware-service helps to provide a unique database name for each tenanted service.
There should be no need to combine the IoT Agent data (services and devices), however there may be a valid use case for combining Context Data coming from separate Tenants (after securing legal agreement from each party of course) - in this case you could create a simple proxy handler which is capable of handling the /v2/op/query and/or /v2/op/update endpoints and forwarding the request with amended headers.
const express = require('express');
const router = express.Router();
const request = require('request-promise');
const BASE_PATH =
process.env.CONTEXT_BROKER || 'http://localhost:1026/v2';
function forwardRequest(req, res) {
// Add necessary validation
const headers = req.headers;
headers['fiware-service' : 'XXXX'];
headers['fiware-servicepath': 'YYYY'];
headers['Accept': 'application/json'];
const options = {
url: BASE_PATH + req.path,
method: req.method,
headers,
json: true
};
request(options)
.then(async function(cbResponse) {
return res.send(compacted);
})
.catch(function(err) {
return res.send(err);
});
}
router.post(
'/op/query', forwardRequest
);
I have been trying to implement HTML5 socket server to broadcast whatever it receives to all its connected clients but have no success.
I am new to sockets, can someone pelase suggest me if there is anything already available opensource or what really is it one has to check for doing so. All i could see is client to server communication but there is no way i can send data from one client to server to the other client or simply put, the server just broadcast all messages to all its connected client??
It sounds like you're trying to achieve peer-to-peer communication, which isn't possible over websockets.
It wouldn't be very difficult to set up a fast broadcast server using Node.js and CoffeeScript, that just echoes everything it receives from one socket to all of the others connected:
net = require 'net'
Array::remove = (e) -> #[t..t] = [] if (t = #indexOf(e)) > -1
class Client
constructor: (#socket) ->
clients = []
server = net.createServer (socket) ->
client = new Client(socket)
clients.push client
socket.addListener 'connect', ->
socket.write "Welcome\r\n"
socket.addListener 'data', (data) ->
for c in clients when c isnt client
c.socket.write data
socket.addListener 'end', ->
clients.remove client
socket.end
.listen 4000
console.log "Chat server is running at localhost:4000"