mirror of
https://gitlab.com/timvisee/send.git
synced 2025-12-08 07:00:54 +03:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7013f5cf80 | ||
|
|
6184a70ba4 | ||
|
|
e264d0da62 | ||
|
|
23a6e338e8 | ||
|
|
2c1dfdbe07 | ||
|
|
994e77a38b | ||
|
|
173ca461a9 | ||
|
|
53426b950a | ||
|
|
9bb36cd827 | ||
|
|
103aa8a0c8 | ||
|
|
62d507120c | ||
|
|
8ccb1c449a | ||
|
|
a07eb1ad1c |
@@ -162,8 +162,8 @@ function download(id, keychain, onprogress, canceller) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
xhr.addEventListener('progress', function(event) {
|
xhr.addEventListener('progress', function(event) {
|
||||||
if (event.lengthComputable && event.target.status === 200) {
|
if (event.target.status === 200) {
|
||||||
onprogress([event.loaded, event.total]);
|
onprogress(event.loaded);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const auth = await keychain.authHeader();
|
const auth = await keychain.authHeader();
|
||||||
@@ -171,7 +171,7 @@ function download(id, keychain, onprogress, canceller) {
|
|||||||
xhr.setRequestHeader('Authorization', auth);
|
xhr.setRequestHeader('Authorization', auth);
|
||||||
xhr.responseType = 'blob';
|
xhr.responseType = 'blob';
|
||||||
xhr.send();
|
xhr.send();
|
||||||
onprogress([0, 1]);
|
onprogress(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export default class FileReceiver extends Nanobus {
|
|||||||
this.fileInfo.name = meta.name;
|
this.fileInfo.name = meta.name;
|
||||||
this.fileInfo.type = meta.type;
|
this.fileInfo.type = meta.type;
|
||||||
this.fileInfo.iv = meta.iv;
|
this.fileInfo.iv = meta.iv;
|
||||||
this.fileInfo.size = meta.size;
|
this.fileInfo.size = +meta.size;
|
||||||
this.state = 'ready';
|
this.state = 'ready';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ export default class FileReceiver extends Nanobus {
|
|||||||
this.fileInfo.id,
|
this.fileInfo.id,
|
||||||
this.keychain,
|
this.keychain,
|
||||||
p => {
|
p => {
|
||||||
this.progress = p;
|
this.progress = [p, this.fileInfo.size];
|
||||||
this.emit('progress');
|
this.emit('progress');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
10339
package-lock.json
generated
10339
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "firefox-send",
|
"name": "firefox-send",
|
||||||
"description": "File Sharing Experiment",
|
"description": "File Sharing Experiment",
|
||||||
"version": "2.5.5",
|
"version": "2.6.1",
|
||||||
"author": "Mozilla (https://mozilla.org)",
|
"author": "Mozilla (https://mozilla.org)",
|
||||||
"repository": "mozilla/send",
|
"repository": "mozilla/send",
|
||||||
"homepage": "https://github.com/mozilla/send/",
|
"homepage": "https://github.com/mozilla/send/",
|
||||||
@@ -114,13 +114,15 @@
|
|||||||
"webpack-unassert-loader": "^1.2.0"
|
"webpack-unassert-loader": "^1.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aws-sdk": "^2.329.0",
|
"@google-cloud/storage": "^2.3.0",
|
||||||
|
"aws-sdk": "^2.349.0",
|
||||||
"babel-polyfill": "^6.26.0",
|
"babel-polyfill": "^6.26.0",
|
||||||
"choo": "^6.13.0",
|
"choo": "^6.13.0",
|
||||||
"cldr-core": "^32.0.0",
|
"cldr-core": "^32.0.0",
|
||||||
"connect-busboy": "0.0.2",
|
"connect-busboy": "0.0.2",
|
||||||
"convict": "^4.4.0",
|
"convict": "^4.4.0",
|
||||||
"express": "^4.16.3",
|
"express": "^4.16.3",
|
||||||
|
"fast-crc32c": "^1.0.4",
|
||||||
"fluent": "^0.6.4",
|
"fluent": "^0.6.4",
|
||||||
"fluent-langneg": "^0.1.0",
|
"fluent-langneg": "^0.1.0",
|
||||||
"helmet": "^3.13.0",
|
"helmet": "^3.13.0",
|
||||||
@@ -143,6 +145,7 @@
|
|||||||
"de",
|
"de",
|
||||||
"dsb",
|
"dsb",
|
||||||
"el",
|
"el",
|
||||||
|
"en-CA",
|
||||||
"es-AR",
|
"es-AR",
|
||||||
"es-CL",
|
"es-CL",
|
||||||
"es-ES",
|
"es-ES",
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ uploadPageDropMessage = გადმოიტანეთ ფაილი აქ
|
|||||||
uploadPageSizeMessage = ყველაზე საიმედო მომსახურება, შეგიძლიათ ატვირთოთ არაუმეტეს 1GB ზომის ფაილი
|
uploadPageSizeMessage = ყველაზე საიმედო მომსახურება, შეგიძლიათ ატვირთოთ არაუმეტეს 1GB ზომის ფაილი
|
||||||
uploadPageBrowseButton = ფაილის არჩევა კომპიუტერიდან
|
uploadPageBrowseButton = ფაილის არჩევა კომპიუტერიდან
|
||||||
uploadPageBrowseButton1 = ფაილის არჩევა ასატვირთად
|
uploadPageBrowseButton1 = ფაილის არჩევა ასატვირთად
|
||||||
uploadPageMultipleFilesAlert = ერთდროულად რამდენიმე ფაილის, ან საქაღალდის ატვირთვა, ამჟამად არაა ხელმისაწვდომი.
|
uploadPageMultipleFilesAlert = ერთდროულად რამდენიმე ფაილის ან საქაღალდის ატვირთვა, ამჟამად არაა ხელმისაწვდომი.
|
||||||
uploadPageBrowseButtonTitle = ფაილის ატვირთვა
|
uploadPageBrowseButtonTitle = ფაილის ატვირთვა
|
||||||
uploadingPageProgress = მიმდინარეობს ატვირთვა { $filename } ({ $size })
|
uploadingPageProgress = მიმდინარეობს ატვირთვა { $filename } ({ $size })
|
||||||
importingFile = გადმოტანა...
|
importingFile = გადმოტანა...
|
||||||
@@ -24,7 +24,7 @@ uploadingPageLargeFileMessage = ფაილი დიდია და ატვ
|
|||||||
uploadingFileNotification = შეტყობინება, ატვირთვის დასრულებისას.
|
uploadingFileNotification = შეტყობინება, ატვირთვის დასრულებისას.
|
||||||
uploadSuccessConfirmHeader = მზადაა გასაგზავნად
|
uploadSuccessConfirmHeader = მზადაა გასაგზავნად
|
||||||
uploadSvgAlt = ატვირთვა
|
uploadSvgAlt = ატვირთვა
|
||||||
uploadSuccessTimingHeader = ფაილს ვადა გაუვა 1 ჩამოტვირთვის, ან 24 საათის მერე.
|
uploadSuccessTimingHeader = ფაილს ვადა გაუვა 1 ჩამოტვირთვის ან 24 საათის მერე.
|
||||||
expireInfo = ფაილის ბმულს, ვადა გაუვა { $downloadCount }, ან { $timespan } მერე.
|
expireInfo = ფაილის ბმულს, ვადა გაუვა { $downloadCount }, ან { $timespan } მერე.
|
||||||
downloadCount =
|
downloadCount =
|
||||||
{ $num ->
|
{ $num ->
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ deletePopupYes = Sim
|
|||||||
deletePopupCancel = Cancelar
|
deletePopupCancel = Cancelar
|
||||||
deleteButtonHover = Apagar
|
deleteButtonHover = Apagar
|
||||||
copyUrlHover = Copiar URL
|
copyUrlHover = Copiar URL
|
||||||
footerLinkLegal = Legal
|
footerLinkLegal = Informações legais
|
||||||
# Test Pilot is a proper name and should not be localized.
|
# Test Pilot is a proper name and should not be localized.
|
||||||
footerLinkAbout = Acerca do Test Pilot
|
footerLinkAbout = Acerca do Test Pilot
|
||||||
footerLinkPrivacy = Privacidade
|
footerLinkPrivacy = Privacidade
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ verifyingFile = Se verifică...
|
|||||||
encryptingFile = Se criptează…
|
encryptingFile = Se criptează…
|
||||||
decryptingFile = Se decriptează…
|
decryptingFile = Se decriptează…
|
||||||
notifyUploadDone = Încărcarea s-a finalizat.
|
notifyUploadDone = Încărcarea s-a finalizat.
|
||||||
uploadingPageMessage = După ce fișierul tău este încărcat vei putea seta opțiuni de expirare.
|
uploadingPageMessage = După ce fișierul tău este încărcat, vei putea seta opțiuni de expirare.
|
||||||
uploadingPageCancel = Anulează încărcarea
|
uploadingPageCancel = Anulează încărcarea
|
||||||
uploadCancelNotification = Încărcarea a fost anulată.
|
uploadCancelNotification = Încărcarea a fost anulată.
|
||||||
uploadingPageLargeFileMessage = Stai calm! Acest fișier este mare. S-ar putea să dureze un timp încărcarea.
|
uploadingPageLargeFileMessage = Stai calm! Acest fișier este mare. S-ar putea să dureze un timp încărcarea.
|
||||||
@@ -68,7 +68,7 @@ fileSizeProgress = ({ $partialSize } din { $totalSize })
|
|||||||
# Firefox Send is a brand name and should not be localized.
|
# Firefox Send is a brand name and should not be localized.
|
||||||
sendYourFilesLink = Încearcă Firefox Send
|
sendYourFilesLink = Încearcă Firefox Send
|
||||||
downloadingPageProgress = Se descarcă { $filename } ({ $size })
|
downloadingPageProgress = Se descarcă { $filename } ({ $size })
|
||||||
downloadingPageMessage = Te rugăm să păstrezi această file deschisă în timp ce preluăm fișierul și îl decriptăm.
|
downloadingPageMessage = Te rugăm să lași această filă deschisă în timp ce preluăm fișierul și îl decriptăm.
|
||||||
errorAltText = Eroare la încărcare
|
errorAltText = Eroare la încărcare
|
||||||
errorPageHeader = Ceva a mers prost!
|
errorPageHeader = Ceva a mers prost!
|
||||||
errorPageMessage = A apărut o eroare la încărcarea fișierului.
|
errorPageMessage = A apărut o eroare la încărcarea fișierului.
|
||||||
@@ -92,7 +92,7 @@ nevermindButton = Uită
|
|||||||
legalHeader = Termeni de utilizare și politica de confidențialitate
|
legalHeader = Termeni de utilizare și politica de confidențialitate
|
||||||
legalNoticeTestPilot = Firefox Send este în prezent un experiment Test Pilot și supus <a>Termenilor de utilizare a serviciului</a> și a <a>Politicii de confidențialitate</a> Test Pilot. Poți afla mai multe despre acest experiment și colectarea sa de date <a>aici</a>.
|
legalNoticeTestPilot = Firefox Send este în prezent un experiment Test Pilot și supus <a>Termenilor de utilizare a serviciului</a> și a <a>Politicii de confidențialitate</a> Test Pilot. Poți afla mai multe despre acest experiment și colectarea sa de date <a>aici</a>.
|
||||||
legalNoticeMozilla = Folosirea site-ului Firefox Send mai este supusă <a>Politicii de confidențialitate pentru site-uri web</a> și a <a>Termenilor de utilizare a site-urilor web</a>.
|
legalNoticeMozilla = Folosirea site-ului Firefox Send mai este supusă <a>Politicii de confidențialitate pentru site-uri web</a> și a <a>Termenilor de utilizare a site-urilor web</a>.
|
||||||
deletePopupText = Ștergi aceast fișier?
|
deletePopupText = Ștergi acest fișier?
|
||||||
deletePopupYes = Da
|
deletePopupYes = Da
|
||||||
deletePopupCancel = Renunță
|
deletePopupCancel = Renunță
|
||||||
deleteButtonHover = Șterge
|
deleteButtonHover = Șterge
|
||||||
@@ -109,12 +109,12 @@ changePasswordButton = Modifică
|
|||||||
passwordTryAgain = Parola este incorectă. Încearcă din nou.
|
passwordTryAgain = Parola este incorectă. Încearcă din nou.
|
||||||
reportIPInfringement = Raportează încălcarea proprietății intelectuale
|
reportIPInfringement = Raportează încălcarea proprietății intelectuale
|
||||||
javascriptRequired = Firefox Send are nevoie de JavaScript
|
javascriptRequired = Firefox Send are nevoie de JavaScript
|
||||||
whyJavascript = De ce are nevoie Firefox Send de JavaScript?
|
whyJavascript = De ce Firefox Send are nevoie de JavaScript?
|
||||||
enableJavascript = Te rugăm să reactivezi JavaScript și să încerci din nou.
|
enableJavascript = Te rugăm să reactivezi JavaScript și să încerci din nou.
|
||||||
# A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
# A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
expiresHoursMinutes = { $hours }h { $minutes }m
|
expiresHoursMinutes = { $hours }h { $minutes }m
|
||||||
# A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
# A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
expiresMinutes = { $minutes } m
|
expiresMinutes = { $minutes }m
|
||||||
# A short status message shown when a password is successfully set
|
# A short status message shown when a password is successfully set
|
||||||
passwordIsSet = Parola a fost setată
|
passwordIsSet = Parola a fost setată
|
||||||
# A short status message shown when the user enters a long password
|
# A short status message shown when the user enters a long password
|
||||||
|
|||||||
4
public/locales/sn/send.ftl
Normal file
4
public/locales/sn/send.ftl
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Firefox Send is a brand name and should not be localized.
|
||||||
|
title = Firefox Send
|
||||||
|
siteFeedback = Zvirikutaurwa
|
||||||
|
uploadPageLearnMore = Dzidza zvimwe
|
||||||
@@ -25,6 +25,7 @@ uploadingFileNotification = Thông báo cho tôi khi tải lên hoàn tất.
|
|||||||
uploadSuccessConfirmHeader = Đã sẵn sàng để Gửi
|
uploadSuccessConfirmHeader = Đã sẵn sàng để Gửi
|
||||||
uploadSvgAlt = Tải lên
|
uploadSvgAlt = Tải lên
|
||||||
uploadSuccessTimingHeader = Liên kết đến tập tin của bạn sẽ hết hạn sau 1 lượt tải về hoặc trong 24 giờ.
|
uploadSuccessTimingHeader = Liên kết đến tập tin của bạn sẽ hết hạn sau 1 lượt tải về hoặc trong 24 giờ.
|
||||||
|
expireInfo = Liên kết đến tập tin của bạn sẽ hết hạn sau { $downloadCount } hoặc { $timespan }.
|
||||||
downloadCount =
|
downloadCount =
|
||||||
{ $num ->
|
{ $num ->
|
||||||
*[other] lượt tải
|
*[other] lượt tải
|
||||||
@@ -40,6 +41,7 @@ deleteFileButton = Xóa tập tin
|
|||||||
sendAnotherFileLink = Gửi tập tin khác
|
sendAnotherFileLink = Gửi tập tin khác
|
||||||
# Alternative text used on the download link/button (indicates an action).
|
# Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Tải về
|
downloadAltText = Tải về
|
||||||
|
downloadsFileList = Tải về
|
||||||
# Used as header in a column indicating the amount of time left before a
|
# Used as header in a column indicating the amount of time left before a
|
||||||
# download link expires (e.g. "10h 5m")
|
# download link expires (e.g. "10h 5m")
|
||||||
timeFileList = Thời gian
|
timeFileList = Thời gian
|
||||||
@@ -99,6 +101,7 @@ footerLinkTerms = Điều khoản
|
|||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Yêu cầu mật khẩu khi tải về tập tin này
|
requirePasswordCheckbox = Yêu cầu mật khẩu khi tải về tập tin này
|
||||||
addPasswordButton = Thêm mật khẩu
|
addPasswordButton = Thêm mật khẩu
|
||||||
|
changePasswordButton = Thay đổi
|
||||||
passwordTryAgain = Sai mật khẩu. Vui lòng thử lại.
|
passwordTryAgain = Sai mật khẩu. Vui lòng thử lại.
|
||||||
reportIPInfringement = Báo cáo vi phạm
|
reportIPInfringement = Báo cáo vi phạm
|
||||||
javascriptRequired = Firefox Send cần JavaScript
|
javascriptRequired = Firefox Send cần JavaScript
|
||||||
@@ -112,3 +115,5 @@ expiresMinutes = { $minutes } phút
|
|||||||
passwordIsSet = Đã đặt mật khẩu
|
passwordIsSet = Đã đặt mật khẩu
|
||||||
# A short status message shown when the user enters a long password
|
# A short status message shown when the user enters a long password
|
||||||
maxPasswordLength = Độ dài mật khẩu tối đa: { $length }
|
maxPasswordLength = Độ dài mật khẩu tối đa: { $length }
|
||||||
|
# A short status message shown when there was an error setting the password
|
||||||
|
passwordSetError = Không thể đặt mật khẩu này
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ footerLinkLegal = 法律
|
|||||||
# Test Pilot is a proper name and should not be localized.
|
# Test Pilot is a proper name and should not be localized.
|
||||||
footerLinkAbout = 关于 Test Pilot
|
footerLinkAbout = 关于 Test Pilot
|
||||||
footerLinkPrivacy = 隐私
|
footerLinkPrivacy = 隐私
|
||||||
footerLinkTerms = 条款
|
footerLinkTerms = 使用条款
|
||||||
footerLinkCookies = Cookie
|
footerLinkCookies = Cookie
|
||||||
requirePasswordCheckbox = 持有密码才能下载此文件
|
requirePasswordCheckbox = 持有密码才能下载此文件
|
||||||
addPasswordButton = 添加密码
|
addPasswordButton = 添加密码
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ const conf = convict({
|
|||||||
default: '',
|
default: '',
|
||||||
env: 'S3_BUCKET'
|
env: 'S3_BUCKET'
|
||||||
},
|
},
|
||||||
|
gcs_bucket: {
|
||||||
|
format: String,
|
||||||
|
default: '',
|
||||||
|
env: 'GCS_BUCKET'
|
||||||
|
},
|
||||||
redis_host: {
|
redis_host: {
|
||||||
format: String,
|
format: String,
|
||||||
default: 'localhost',
|
default: 'localhost',
|
||||||
|
|||||||
@@ -6,13 +6,6 @@ module.exports = async function(req, res) {
|
|||||||
const id = req.params.id;
|
const id = req.params.id;
|
||||||
try {
|
try {
|
||||||
const meta = req.meta;
|
const meta = req.meta;
|
||||||
const contentLength = await storage.length(id);
|
|
||||||
res.writeHead(200, {
|
|
||||||
'Content-Disposition': 'attachment',
|
|
||||||
'Content-Type': 'application/octet-stream',
|
|
||||||
'Content-Length': contentLength,
|
|
||||||
'WWW-Authenticate': `send-v1 ${req.nonce}`
|
|
||||||
});
|
|
||||||
const file_stream = storage.get(id);
|
const file_stream = storage.get(id);
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
|
|
||||||
@@ -21,7 +14,7 @@ module.exports = async function(req, res) {
|
|||||||
file_stream.destroy();
|
file_stream.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
file_stream.on('end', async () => {
|
file_stream.pipe(res).on('finish', async () => {
|
||||||
if (cancelled) {
|
if (cancelled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -38,8 +31,6 @@ module.exports = async function(req, res) {
|
|||||||
log.info('StorageError:', id);
|
log.info('StorageError:', id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
file_stream.pipe(res);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
res.sendStatus(404);
|
res.sendStatus(404);
|
||||||
}
|
}
|
||||||
|
|||||||
37
server/storage/gcs.js
Normal file
37
server/storage/gcs.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
const { Storage } = require('@google-cloud/storage');
|
||||||
|
const storage = new Storage();
|
||||||
|
|
||||||
|
class GCSStorage {
|
||||||
|
constructor(config, log) {
|
||||||
|
this.bucket = storage.bucket(config.gcs_bucket);
|
||||||
|
this.log = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
async length(id) {
|
||||||
|
const data = await this.bucket.file(id).getMetadata();
|
||||||
|
return data[0].size;
|
||||||
|
}
|
||||||
|
|
||||||
|
getStream(id) {
|
||||||
|
return this.bucket.file(id).createReadStream({ validation: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
set(id, file) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
file
|
||||||
|
.pipe(this.bucket.file(id).createWriteStream())
|
||||||
|
.on('error', reject)
|
||||||
|
.on('finish', resolve);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
del(id) {
|
||||||
|
return this.bucket.file(id).delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
ping() {
|
||||||
|
return this.bucket.exists();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = GCSStorage;
|
||||||
@@ -5,7 +5,14 @@ const createRedisClient = require('./redis');
|
|||||||
|
|
||||||
class DB {
|
class DB {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
const Storage = config.s3_bucket ? require('./s3') : require('./fs');
|
let Storage = null;
|
||||||
|
if (config.s3_bucket) {
|
||||||
|
Storage = require('./s3');
|
||||||
|
} else if (config.gcs_bucket) {
|
||||||
|
Storage = require('./gcs');
|
||||||
|
} else {
|
||||||
|
Storage = require('./fs');
|
||||||
|
}
|
||||||
this.log = mozlog('send.storage');
|
this.log = mozlog('send.storage');
|
||||||
this.expireSeconds = config.expire_seconds;
|
this.expireSeconds = config.expire_seconds;
|
||||||
this.storage = new Storage(config, this.log);
|
this.storage = new Storage(config, this.log);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
selenium==3.14.0
|
selenium==3.141.0
|
||||||
flake8==3.5.0
|
flake8==3.6.0
|
||||||
flake8-isort==2.5
|
flake8-isort==2.5
|
||||||
PyPOM==2.1.0
|
PyPOM==2.2.0
|
||||||
pytest==3.8.0
|
pytest==3.10.0
|
||||||
pytest-html==1.19.0
|
pytest-html==1.19.0
|
||||||
pytest-selenium==1.14.0
|
pytest-selenium==1.14.0
|
||||||
pytest-xdist==1.23.0
|
pytest-xdist==1.24.0
|
||||||
|
|||||||
Reference in New Issue
Block a user