diff --git a/.dockerignore b/.dockerignore
index 3765648b1..8b26d6a73 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,3 +1,5 @@
*
!dist
!build
+!metadata.json
+!docker-extension/build
diff --git a/api/cli/cli.go b/api/cli/cli.go
index f04804cd3..8a2ee9c19 100644
--- a/api/cli/cli.go
+++ b/api/cli/cli.go
@@ -51,7 +51,7 @@ func (*Service) ParseFlags(version string) (*portainer.CLIFlags, error) {
SSLKey: kingpin.Flag("sslkey", "Path to the SSL key used to secure the Portainer instance").String(),
Rollback: kingpin.Flag("rollback", "Rollback the database store to the previous version").Bool(),
SnapshotInterval: kingpin.Flag("snapshot-interval", "Duration between each environment snapshot job").String(),
- AdminPassword: kingpin.Flag("admin-password", "Hashed admin password").String(),
+ AdminPassword: kingpin.Flag("admin-password", "Set admin password with provided hash").String(),
AdminPasswordFile: kingpin.Flag("admin-password-file", "Path to the file containing the password for the admin user").String(),
Labels: pairs(kingpin.Flag("hide-label", "Hide containers with a specific label in the UI").Short('l')),
Logo: kingpin.Flag("logo", "URL for the logo displayed in the UI").String(),
diff --git a/api/crypto/hash.go b/api/crypto/hash.go
index 3e52dfbd3..d9b212bf3 100644
--- a/api/crypto/hash.go
+++ b/api/crypto/hash.go
@@ -9,11 +9,11 @@ type Service struct{}
// Hash hashes a string using the bcrypt algorithm
func (*Service) Hash(data string) (string, error) {
- hash, err := bcrypt.GenerateFromPassword([]byte(data), bcrypt.DefaultCost)
+ bytes, err := bcrypt.GenerateFromPassword([]byte(data), bcrypt.DefaultCost)
if err != nil {
- return "", nil
+ return "", err
}
- return string(hash), nil
+ return string(bytes), err
}
// CompareHashAndData compares a hash to clear data and returns an error if the comparison fails.
diff --git a/api/crypto/hash_test.go b/api/crypto/hash_test.go
new file mode 100644
index 000000000..bc73be3a5
--- /dev/null
+++ b/api/crypto/hash_test.go
@@ -0,0 +1,53 @@
+package crypto
+
+import (
+ "testing"
+)
+
+func TestService_Hash(t *testing.T) {
+ var s = &Service{}
+
+ type args struct {
+ hash string
+ data string
+ }
+ tests := []struct {
+ name string
+ args args
+ expect bool
+ }{
+ {
+ name: "Empty",
+ args: args{
+ hash: "",
+ data: "",
+ },
+ expect: false,
+ },
+ {
+ name: "Matching",
+ args: args{
+ hash: "$2a$10$6BFGd94oYx8k0bFNO6f33uPUpcpAJyg8UVX.akLe9EthF/ZBTXqcy",
+ data: "Passw0rd!",
+ },
+ expect: true,
+ },
+ {
+ name: "Not matching",
+ args: args{
+ hash: "$2a$10$ltKrUZ7492xyutHOb0/XweevU4jyw7QO66rP32jTVOMb3EX3JxA/a",
+ data: "Passw0rd!",
+ },
+ expect: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+
+ err := s.CompareHashAndData(tt.args.hash, tt.args.data)
+ if (err != nil) == tt.expect {
+ t.Errorf("Service.CompareHashAndData() = %v", err)
+ }
+ })
+ }
+}
diff --git a/api/filesystem/write.go b/api/filesystem/write.go
index 235511933..1e4b714a0 100644
--- a/api/filesystem/write.go
+++ b/api/filesystem/write.go
@@ -7,6 +7,7 @@ import (
"github.com/pkg/errors"
)
+// WriteToFile creates a file in the filesystem storage
func WriteToFile(dst string, content []byte) error {
if err := os.MkdirAll(filepath.Dir(dst), 0744); err != nil {
return errors.Wrapf(err, "failed to create filestructure for the path %q", dst)
diff --git a/api/portainer.go b/api/portainer.go
index 2f942ea82..ca5711247 100644
--- a/api/portainer.go
+++ b/api/portainer.go
@@ -1344,7 +1344,7 @@ type (
const (
// APIVersion is the version number of the Portainer API
- APIVersion = "2.11.0"
+ APIVersion = "2.11.1"
// DBVersion is the version number of the Portainer database
DBVersion = 35
// ComposeSyntaxMaxVersion is a maximum supported version of the docker compose syntax
diff --git a/app/config.js b/app/config.js
index 2cac8c5dc..d701ee818 100644
--- a/app/config.js
+++ b/app/config.js
@@ -14,6 +14,7 @@ export function configApp($urlRouterProvider, $httpProvider, localStorageService
tokenGetter: /* @ngInject */ function tokenGetter(LocalStorage) {
return LocalStorage.getJWT();
},
+ whiteListedDomains: ['localhost'],
});
$httpProvider.interceptors.push('jwtInterceptor');
diff --git a/app/docker/views/containers/console/containerConsoleController.js b/app/docker/views/containers/console/containerConsoleController.js
index ab2e92d6c..940bd30ba 100644
--- a/app/docker/views/containers/console/containerConsoleController.js
+++ b/app/docker/views/containers/console/containerConsoleController.js
@@ -69,9 +69,9 @@ angular.module('portainer.docker').controller('ContainerConsoleController', [
id: attachId,
};
+ const base = window.location.origin.startsWith('http') ? `${window.location.origin}${baseHref()}` : baseHref();
var url =
- window.location.origin +
- baseHref() +
+ base +
'api/websocket/attach?' +
Object.keys(params)
.map((k) => k + '=' + params[k])
@@ -110,9 +110,9 @@ angular.module('portainer.docker').controller('ContainerConsoleController', [
id: data.Id,
};
+ const base = window.location.origin.startsWith('http') ? `${window.location.origin}${baseHref()}` : baseHref();
var url =
- window.location.origin +
- baseHref() +
+ base +
'api/websocket/exec?' +
Object.keys(params)
.map((k) => k + '=' + params[k])
diff --git a/app/global.d.ts b/app/global.d.ts
index a8842eefe..3ae967ca1 100644
--- a/app/global.d.ts
+++ b/app/global.d.ts
@@ -18,3 +18,7 @@ declare module 'axios-progress-bar' {
instance?: AxiosInstance
): void;
}
+
+interface Window {
+ ddExtension: boolean;
+}
diff --git a/app/index.html b/app/index.html
index 920e1af72..8748fde19 100644
--- a/app/index.html
+++ b/app/index.html
@@ -7,9 +7,16 @@