mattnenterprise / rust-ftp Goto Github PK
View Code? Open in Web Editor NEWFTP client for Rust
License: Apache License 2.0
FTP client for Rust
License: Apache License 2.0
When I try some general command, e.g. LIST, I got below error:
Err(InvalidResponse("Expected code [227], got response: 550 Unknown error.\r\n"))
As my FTP server doesn't support PASV mode, so it's better to have some flag to disable it in the client also.
Some type of testing is needed to ensure the code still works when changes are made. We can test against a pure-ftpd server.
See Title.
Currently the README doesn't show how to enable them. I believe the current version of the README only shows support for turning on secure mode which I believe uses openssl by default.
I was trying to connect anonymously to ftp.hq.nasa.gov
but I'm getting an "Invalid response". I suspect there is something wrong in read_response
:
// nasa.rs
extern crate ftp;
use std::str;
use ftp::FTPStream;
fn main() {
let mut ftp_stream = match FTPStream::connect("198.116.65.45".to_string(), 21) {
Ok(s) => s,
Err(e) => panic!("{}", e)
};
}
Here is a capture:
ftp_failure.pcapng.zip
I need MLSD command.
Are there any plans for implementation?
Hey there, thanks for the great library!
On compiling with ftp 3.0.1 I get the following error:
❯ cargo b -r --future-incompat-report
Finished release [optimized] target(s) in 0.13s
warning: the following packages contain code that will be rejected by a future version of Rust: winapi v0.2.8
note:
To solve this problem, you can try the following approaches:
- Some affected dependencies have newer versions available.
You may want to consider updating them to a newer version to see if the issue has been fixed.
winapi v0.2.8 has the following newer versions available: 0.3.0, 0.3.1, 0.3.2, 0.3.3, 0.3.4, 0.3.5, 0.3.6, 0.3.7, 0.3.8, 0.3.9
- If the issue is not solved by updating the dependencies, a fix has to be
implemented by those dependencies. You can help with that by notifying the
maintainers of this problem (e.g. by creating a bug report) or by proposing a
fix to the maintainers (e.g. by creating a pull request):
- [email protected]
- Repository: https://github.com/retep998/winapi-rs
- Detailed warning command: `cargo report future-incompatibilities --id 14 --package [email protected]`
- If waiting for an upstream fix is not an option, you can use the `[patch]`
section in `Cargo.toml` to use your own version of the dependency. For more
information, see:
https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html#the-patch-section
note: this report can be shown with `cargo report future-incompatibilities --id 14`
It seems like winapi is required by the following sequence:
ftp v3.0.1
└── regex v0.1.80
└── thread_local v0.2.7
└── thread-id v2.0.0
└── kernel32-sys v0.2.2
└── winapi v0.2.8
Is there any chance to update these? Maybe a regex update might already suffice, or we might need to pass it down.
Trying to use the library (on file who made 80Mo), I get a file with 81677962 bytes which become after the download to a size of 81969152.
I have take a look on the difference, and I found some additional bytes on 0x0A
which was converted to 0x0D 0x0A
.
Do you have any idea of the issue ?
Im not sure if that is the right place but when I run cargo audit
on the duckscript
repo I get this error:
https://github.com/sagiegurari/duckscript
$ cargo audit
Fetching advisory database from `https://github.com/RustSec/advisory-db.git`
Loaded 416 security advisories (from /Users/john/.cargo/advisory-db)
Updating crates.io index
Scanning Cargo.lock for vulnerabilities (124 crate dependencies)
Crate: regex
Version: 0.1.80
Title: Regexes with large repetitions on empty sub-expressions take a very long time to parse
Date: 2022-03-08
ID: RUSTSEC-2022-0013
URL: https://rustsec.org/advisories/RUSTSEC-2022-0013
Solution: Upgrade to >=1.5.5
Dependency tree:
regex 0.1.80
└── ftp 3.0.1
└── duckscriptsdk 0.8.12
└── duckscript_cli 0.8.12
Crate: thread_local
Version: 0.2.7
Title: Data race in `Iter` and `IterMut`
Date: 2022-01-23
ID: RUSTSEC-2022-0006
URL: https://rustsec.org/advisories/RUSTSEC-2022-0006
Solution: Upgrade to >=1.1.4
Dependency tree:
thread_local 0.2.7
└── regex 0.1.80
└── ftp 3.0.1
└── duckscriptsdk 0.8.12
└── duckscript_cli 0.8.12
error: 2 vulnerabilities found!
So I'm not sure if that's the rust-ftp
that has an old regex
version or duckscript
if its duckscript
I will move my issue there.
I make a test to upload files with format: Zip, Rar,MSI, Exe, etc and always the file when it's uploaded its modified and then broken when it's downloaded and try to open.
on the other hand if i upload files type text like .txt, .php,.html,.js , etc i don't experiment any problem.
here it's the code example
use std::fs::{read, write};
use std::str;
use std::io::Cursor;
use ftp::FtpStream;
fn main() {
let mut ftp_stream = FtpStream::connect("somehost.com:21").unwrap();
let _ = ftp_stream.login("some_user", "some_password").unwrap();
let read_bytes = read("test_file.rar").unwrap();
let bytes = read_bytes.as_slice();
println!("Total bytes read : {}",read_bytes.iter().count());
let mut reader = Cursor::new(bytes);
let bytes_reader = reader.clone().into_inner();
println!("Totalt bytes after reader {}",bytes_reader.iter().count());
ftp_stream.cwd("public_html").unwrap();
let _ = ftp_stream.put("file.rar", &mut reader);
}
'till this moment i know the problem exist when make the stream of the bytes, 'cause if i write the bytes of the reader on my disk the file it's OK.
So i will check the code of the stream to see what's it's going on.
Tested ON: Windows 10 21H2 and Mac OS Monterrey 12.6
Port 21 is the default port that an FTP client should try to use to connect to a provided address if no port is specified. It should be perfectly reasonable for someone to create an FtpStream
with the address "127.0.0.1"
and have the client implicitly use port 21.
Currently, if the port is left out of the address string, a Custom
error with kind
InvalidInput
and error
StringError("invalid socket address")
is returned.
$ cargo run
Updating registry https://github.com/rust-lang/crates.io-index
Downloading ftp v0.0.4
Downloading regex-syntax v0.1.2
Downloading regex v0.1.33
Compiling regex-syntax v0.1.2
Compiling regex v0.1.33
Compiling ftp v0.0.4
/home/dmitry/.cargo/registry/src/github.com-1285ae84e5963aae/ftp-0.0.4/src/ftp.rs:8:19: 8:27 error: unresolved import std::old_io::IoResult
. Could not find old_io
in std
/home/dmitry/.cargo/registry/src/github.com-1285ae84e5963aae/ftp-0.0.4/src/ftp.rs:8 use std::old_io::{IoResult, TcpStream, BufferedReader, BufferedWriter, MemReader, EndOfFile};
^~~~~~~~
/home/dmitry/.cargo/registry/src/github.com-1285ae84e5963aae/ftp-0.0.4/src/ftp.rs:8:29: 8:38 error: unresolved import std::old_io::TcpStream
. Could not find old_io
in std
/home/dmitry/.cargo/registry/src/github.com-1285ae84e5963aae/ftp-0.0.4/src/ftp.rs:8 use std::old_io::{IoResult, TcpStream, BufferedReader, BufferedWriter, MemReader, EndOfFile};
^~~~~~~~~
/home/dmitry/.cargo/registry/src/github.com-1285ae84e5963aae/ftp-0.0.4/src/ftp.rs:8:40: 8:54 error: unresolved import std::old_io::BufferedReader
. Could not find old_io
in std
/home/dmitry/.cargo/registry/src/github.com-1285ae84e5963aae/ftp-0.0.4/src/ftp.rs:8 use std::old_io::{IoResult, TcpStream, BufferedReader, BufferedWriter, MemReader, EndOfFile};
^~~~~~~~~~~~~~
/home/dmitry/.cargo/registry/src/github.com-1285ae84e5963aae/ftp-0.0.4/src/ftp.rs:8:56: 8:70 error: unresolved import std::old_io::BufferedWriter
. Could not find old_io
in std
/home/dmitry/.cargo/registry/src/github.com-1285ae84e5963aae/ftp-0.0.4/src/ftp.rs:8 use std::old_io::{IoResult, TcpStream, BufferedReader, BufferedWriter, MemReader, EndOfFile};
^~~~~~~~~~~~~~
/home/dmitry/.cargo/registry/src/github.com-1285ae84e5963aae/ftp-0.0.4/src/ftp.rs:8:72: 8:81 error: unresolved import std::old_io::MemReader
. Could not find old_io
in std
/home/dmitry/.cargo/registry/src/github.com-1285ae84e5963aae/ftp-0.0.4/src/ftp.rs:8 use std::old_io::{IoResult, TcpStream, BufferedReader, BufferedWriter, MemReader, EndOfFile};
^~~~~~~~~
/home/dmitry/.cargo/registry/src/github.com-1285ae84e5963aae/ftp-0.0.4/src/ftp.rs:8:83: 8:92 error: unresolved import std::old_io::EndOfFile
. Could not find old_io
in std
/home/dmitry/.cargo/registry/src/github.com-1285ae84e5963aae/ftp-0.0.4/src/ftp.rs:8 use std::old_io::{IoResult, TcpStream, BufferedReader, BufferedWriter, MemReader, EndOfFile};
^~~~~~~~~
/home/dmitry/.cargo/registry/src/github.com-1285ae84e5963aae/ftp-0.0.4/src/ftp.rs:11:5: 11:28 error: unresolved import std::old_io::util::copy
. Could not find old_io
in std
/home/dmitry/.cargo/registry/src/github.com-1285ae84e5963aae/ftp-0.0.4/src/ftp.rs:11 use std::old_io::util::copy;
^~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 7 previous errors
Could not compile ftp
.
To learn more, run the command again with --verbose.
$ rustc --version
rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)
Taking a new look at this crate after several months, it's looking great!
I have a few ideas to make the code more ergonomic, for instance replacing explicit drops by out-of-scope automatic drops, using AsRef<&str> or Into<Cow<'a, str>>, rewriting simple_retr_ to avoid a clone, this kind of things. Would you be interested in a PR with these changes?
The passed in closure is only called once, so it should be able to be a FnOnce
, not a Fn
.
I'm using Ubuntu server 16.04.
Program:
extern crate ftp;
use ftp::openssl::ssl::*;
fn main() {
let ftp_stream = ftp::FtpStream::connect("127.0.0.1:21").unwrap();
let ctx = SslContext::new(SslMethod::Sslv23).unwrap();
let ssl = Ssl::new(&ctx).unwrap();
// Switch to the secure mode
let mut ftp_stream = ftp_stream.into_secure(ssl).unwrap();
ftp_stream.login("account", "passwd").unwrap();
let v_list = ftp_stream.nlst(Some("/")).unwrap();
let _ = ftp_stream.quit();
}
Error:
thread 'main' panicked at 'called Result::unwrap() on an Err value: InvalidResponse("error: could not parse reply code: invalid digit found in string")', /checkout/src/libcore/result.rs:860:4
I tried with other values or even None for list() and nlst() with no luck. cwd() and pwd() work.
The function data_command
always uses the default SSL_CONTEXT
global to establish a secure connection. I missed this when I added the secure_with_ssl
function. Perhaps a new field should be added to FtpStream
to have it hold onto a reference (or perhaps even clone, for simplicity?) an SslContext
so that we can reuse a user-provided instance instead of the default in all cases?
Hello !
We were working on a fork of your repo to allow ssl session reuse and planning to offer a PR once stabilized, however there's no way to implement this since #92 as native_tls doesn't offer an interface to use sessions reuse. This is actually quite problematique as some servers require to use session reuse when in passive mode.
Apparently the change to native_tls was made in #92 to make it easier to run on Windows and MacOs machine
. As I use ArchLinux I have no idea how much easier it is, however I would like to point out that more than 90% of cloud based webservers run on linux. Since native_tls uses three different crates to implement ssl the configuration available is actually minimal when openssl provides a large set of parameters. This can be easily seen in the number of functions in the builders, 61 for SslConnectorBuilder versus 9 for TlsConnectorBuilder. As an example, I've added at the end how we can implement session reuse with openssl. Therefore I'm not sure the flexibility loss is worth it and would love to read more arguments againts it.
I see three possible solutions:
secure-openssl
and secure-native-tls
that would basically use openssl or native_tls (I can provide a PR)@mattnenterprise Please tell me which which solution you prefer 🙂
Thanks and have a nice day !
Basically it ends up in replacing the function data_command
(taken from version 3.0.1) from:
/// Execute command which send data back in a separate stream
#[cfg(feature = "secure")]
fn data_command(&mut self, cmd: &str) -> Result<DataStream> {
self.pasv()
.and_then(|addr| self.write_str(cmd).map(|_| addr))
.and_then(|addr| TcpStream::connect(addr).map_err(|e| FtpError::ConnectionError(e)))
.and_then(|stream| {
match self.ssl_cfg {
Some(ref ssl) => {
Ssl::new(ssl).unwrap().connect(stream)
.map(|stream| DataStream::Ssl(stream))
.map_err(|e| FtpError::SecureError(e.description().to_owned()))
},
None => Ok(DataStream::Tcp(stream))
}
})
}
To:
/// Execute command which send data back in a separate stream
#[cfg(feature = "secure")]
fn data_command(&mut self, cmd: &str) -> Result<DataStream> {
self.pasv()
.and_then(|addr| self.write_str(cmd).map(|_| addr))
.and_then(|addr| TcpStream::connect(addr).map_err(|e| FtpError::ConnectionError(e)))
.and_then(|stream| match self.ssl_cfg {
Some(ref ssl) => {
let mut ssl = Ssl::new(ssl).unwrap();
match self.reader.get_ref() {
DataStream::Tcp(_) => {}
DataStream::Ssl(ssl_stream) => unsafe {
// SAFETY: ssl_stream was also using the context from self.ssl_cfg
ssl.set_session(ssl_stream.ssl().session().unwrap())
.map_err(|e| FtpError::SecureError(format!("{}", e)))?
},
}
ssl.connect(stream)
.map(|stream| DataStream::Ssl(stream))
.map_err(|e| FtpError::SecureError(format!("{}", e)))
}
None => Ok(DataStream::Tcp(stream)),
})
}
Yet another weird error.
The put function works, the file gets updated, but it still crashes when it gets out, returning a 426 error code.
Edit: after reading a little bit on the internet, this can be an issue on my side only. I will test with another machine to see if this is it.
Hi
The host
parameter for FTPStream::connect
has the type &'static str
. If I understand it correctly, this means that the FTP host that a user connects to needs to be known at compile time, right?
It would probably be a good idea to change that to either a &str
if the value can be borrowed, or to a String
if it needs to be owned.
Everything is in the title.
Clippy
Inconvenience:
As always, I will test this in a separate branch and commit a PR if I find that it works well.
i don't figure out how save all files by wildcard, example **.txt*
for example from documentation we can save one file:
let result = ftp_stream.retr("test.txt", |stream| {
let mut file = File::create("test.txt").unwrap();
let mut buf = [0; 2048];
loop {
match stream.read(&mut buf) {
Ok(0) => break,
Ok(n) => file.write_all(&buf[0..n]).unwrap(),
Err(err) => return Err(err)
};
}
Ok(())
});
Would be nice to have an example of how to properly download/upload a large file, avoiding the control stream timeout (null command)... I'm relatively new to rust and just trying to get a grasp of this.
I have an issue when building a project that use ftp 'Unable to detect OpenSSL version
from here you can see that we need to upgrade openssl, I saw that we had the same issue before so why we don't move to rusttls which is newer than OpenSSL, and doesn't provide any support for TLS 1.1 and older, or any known-insecure algorithms. As a consequence, it's a lot simpler than OpenSSL, and is built purely in Rust, so doesn't require any magic to cross-compile.
As far as I can tell, currently there's no way to set the used TCPStream's read/write timeout. Doing so would be very handy if the server is unresponsive. If this isn't too hard to do, I'd love to contribute a Pull Request. What do you think?
Hi.
According to the RFC, the CDUP command should return 200, not 250 (like the CWD command), so this line is incorrect.
Thanks to fix this issue.
Cross compilation of openssl is virtually impossible
Whether native-tls
or openssl
is used does not change anything as for example cross compiling from Mac to Linux even with native-tls
enabled would require the openssl
libs.
But rustls is a pure Rust implementation, thus shall solve all these issues and beyond
Please consider updating rust-openssl dependency to ^0.10.0
Line 34 in f0e4717
For instance: make_dir => mkdir, current_dir => pwd, change_dir => cwd (or cd?), change_dir_to_parent => cdup, retr => get, stor => put, etc.
For listing the contents of a folder (pull request #20 ), use list or ls?
Small issue really, but it would make it easier to reuse for other functions (maybe list?)
This is something that I have seen some other crates do, and it would be quite helpful for users of this crate. I have no idea how Github pages are set up though. @mattnenterprise what is your opinion on this?
Hi,
I wonder what the current status is given that there are a bunch of PRs being open that fixes some fairly important issues (such as version of openssl) is this crate still being supported or not?
Hi
It would be nice if this library would use a custom error type for all results, instead of mixing io::Error
and String
s. This would play well together with the From<Error>
trait.
Make pasv() use the host returned by the FTP server, rather than self.host (after which probably self.host wouldn't be needed anymore, and the constructor of FtpStream could just take a ToSocketAddrs directly).
And remove command_port too.
Could you update to at least the version alpha of Rust, please? (I tried to build with the nightly version launched after the alpha release but couldn't)
I tried to fix the errors myself but I'm still to new to rust, thanks.
When connecting to an IIS ftp server we stumble upon the following error message:
FTP - quit: InvalidResponse("Expected code [221], got response: 150 Opening BINARY mode data connection.")
I tried to upload the image and the zip, but I found that they were all corrupted.
Seems FTPS doc is outdated
error: no method named `secure` found for type `ftp::FtpStream` in the current scope
--> src/main.rs:9:42
|
9 | let (mut ftp_stream, _) = ftp_stream.secure();
| ^^^^^^
error: aborting due to previous error
My Cargo.toml
[package]
name = "test_app"
version = "0.1.0"
authors = ["Redacted"]
[dependencies]
ftp = { version = "*", features = ["secure"]
Would you be happy for people still use this crate ?
e.g. say if I would send a security related PR or issue would you be open to merge / address ?
Would you like them privately or raise an issue here ? Thanks
Cheers
It would nice to be able to resume partial downloads by specifying the bytes offset from which to read from.
Python's ftplib supports this and can be a good reference source:
FTP.retrbinary(cmd, callback, blocksize=8192, rest=None)
Retrieve a file in binary transfer mode. [...]
rest means the same thing as in thetransfercmd()
method.
FTP.transfercmd(cmd, rest=None)
[...]
If optional rest is given, a REST command is sent to the server, passing rest as an argument. rest is usually a byte offset into the requested file, telling the server to restart sending the file’s bytes at the requested offset, skipping over the initial bytes. .....
Now the user should issue QUIT
manually and I think that should be automated. I suggest implement Drop
trait and issue quit
on drop and probably make the function private.
Also, apply rustfmt on status.rs
Currently having an issue to get a file listing from the FreeBSD ftp archive. The following code fails:
let host = "ftp-archive.freebsd.org:21";
let path = "/mirror/FreeBSD-Archive/old-releases/i386/2.2.8-RELEASE/packages/Latest";
let mut ftp = ftp::FtpStream::connect(host).unwrap();
ftp.login("anonymous", "").unwrap();
let lst = ftp.list(Some(path)).unwrap();
for i in lst {
println!("LIST: {}", i);
}
Using strace I can see that a new passive connection is opened and I can see that the file listing is received, but list() only returns after the server eventually replies with a "426 Data connection: Bad file descriptor.".
This is with rustc 1.15.0-nightly (ba872f270 2016-11-17) and ftp 2.0.0 on Linux.
I've tried get and retr and neither seem to return a BufRead
I ask because i'm trying to use read_line https://doc.rust-lang.org/beta/std/io/trait.BufRead.html#method.read_line
let mut ftp_stream = FtpStream::connect(("ftp.arin.net", 21)).unwrap();
ftp_stream.login("anonymous", "").unwrap();
println!("current dir: {}", ftp_stream.pwd().unwrap());
ftp_stream.cwd("pub/stats/arin").unwrap();
let stream = ftp_stream.get("delegated-arin-extended-latest").unwrap();
let mut buf = Vec::new();
let num_bytes = stream.read_line(&mut buf);
println!("got line: {}", str::from_utf8(&buf).unwrap());
let num_bytes = stream.read_line(&mut buf);
println!("got line: {}", str::from_utf8(&buf).unwrap());
error[E0599]: no method named `read_line` found for type `std::io::BufReader<ftp::data_stream::DataStream>` in the current scope
This issue was automatically generated. Feel free to close without ceremony if
you do not agree with re-licensing or if it is not possible for other reasons.
Respond to @cmr with any questions or concerns, or pop over to
#rust-offtopic
on IRC to discuss.
You're receiving this because someone (perhaps the project maintainer)
published a crates.io package with the license as "MIT" xor "Apache-2.0" and
the repository field pointing here.
The MIT license requires reproducing countless copies of the same copyright
header with different names in the copyright field, for every MIT library in
use. The Apache license does not have this drawback. However, this is not the
primary motivation for me creating these issues. The Apache license also has
protections from patent trolls and an explicit contribution licensing clause.
However, the Apache license is incompatible with GPLv2. This is why Rust is
dual-licensed as MIT/Apache (the "primary" license being Apache, MIT only for
GPLv2 compat), and doing so would be wise for this project. This also makes
this crate suitable for inclusion and unrestricted sharing in the Rust
standard distribution and other projects using dual MIT/Apache, such as my
personal ulterior motive, the Robigalia project.
Some ask, "Does this really apply to binary redistributions? Does MIT really
require reproducing the whole thing?" I'm not a lawyer, and I can't give legal
advice, but some Google Android apps include open source attributions using
this interpretation. Others also agree with
it.
But, again, the copyright notice redistribution is not the primary motivation
for the dual-licensing. It's stronger protections to licensees and better
interoperation with the wider Rust ecosystem.
To do this, get explicit approval from each contributor of copyrightable work
(as not all contributions qualify for copyright) and then add the following to
your README:
## License
Licensed under either of
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.
and in your license headers, use the following boilerplate (based on that used in Rust):
// Copyright (c) 2016 rust-ftp developers
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.
Be sure to add the relevant LICENSE-{MIT,APACHE}
files. You can copy these
from the Rust repo for a plain-text
version.
And don't forget to update the license
metadata in your Cargo.toml
to:
license = "MIT/Apache-2.0"
I'll be going through projects which agree to be relicensed and have approval
by the necessary contributors and doing this changes, so feel free to leave
the heavy lifting to me!
To agree to relicensing, comment with :
I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option
My scripts will pick this exact phrase up and check your checkbox, but I'll
come through and manually review this issue later as well.
This one is only for ease of use:
It would be great if the list function return a Struct containing all of the information in the String.
I will do yet another pull request adding the code that I made for this, but I would like the openssl issue #69 to be resolved first because the list function doesn't work without this update.
Can we update
[dependencies.openssl] to rust-OpenSSL 0.9 ?
0.7 no longer compiles on the latest Fedora / Linux
Cargo audit failed
cargo check
cargo audit
Fetching advisory database from `https://github.com/RustSec/advisory-db.git`
Loaded 433 security advisories (from /home/balrog/.cargo/advisory-db)
Updating crates.io index
Scanning Cargo.lock for vulnerabilities (57 crate dependencies)
Crate: time
Version: 0.1.44
Title: Potential segfault in the time crate
Date: 2020-11-18
ID: RUSTSEC-2020-0071
URL: https://rustsec.org/advisories/RUSTSEC-2020-0071
Solution: Upgrade to >=0.2.23
Dependency tree:
time 0.1.44
└── chrono 0.4.20
└── ftp 3.0.1
error: 1 vulnerability found!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.