CICD với GITLAB
StrictHostKeyChecking là để đảm bảo bạn đang connect đến đúng cái server mà bạn muốn, để bảo vệ bạn khỏi tấn công man-in-the-middle. Nếu bạn tự tin server chạy runner không thể bị tấn công kiểu này thì bạn có thể tắt đi cho đơn giản. Còn cách làm đầy đủ thì bạn lấy host key trên server như thế này.
cat /etc/ssh/ssh_host_*_key.pub | awk '{print "<IP hoặc hostname của server bạn dùng để SSH> " $1 " " $2}'
Sau đó lưu output thành một secret file tên là SSH_KNOWN_HOSTS
trên Gitlab rồi trong script CI bạn thêm
- mkdir -p ~/.ssh
- cp "$SSH_KNOWN_HOSTS" ~/.ssh/known_hosts
- chmod 0644 ~/.ssh/known_hosts
Hướng dẫn chi tiết hơn thì ở đây nhé https://docs.gitlab.com/ee/ci/jobs/ssh_keys.html#verifying-the-ssh-host-keys.
Còn SSH command không có npm với node thì bạn check trong file ~/.bashrc
, mặc định của Ubuntu và Debian thường sẽ có đoạn này.
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
Tức là nếu bạn chạy command qua SSH thì nó sẽ không chạy đoạn ở sau nữa, nên nếu bạn setup PATH=$PATH:...
ở cuối file như thường làm thì sẽ không có tác dụng nên sẽ không tìm được binary của node và npm. Bạn có thể cho đoạn setup PATH
lên trước đoạn này. Hoặc nếu dùng nvm thì chuyển đoạn này lên trên
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ]
Ngoài ra thì có thể dùng full path của node và npm. Bạn SSH vào server rồi chạy which npm
để lấy full path của binary rồi trong script thì bạn dùng cái full path đấy.
Tại sao Access Token không thể thay thế được cho Refresh Token? Refresh Token bảo mật hơn Access Token như thế nào? Tại sao chúng ta thực sự cần Refresh Token?
Thường thì refresh token sẽ yêu cầu client ID và secret để tạo access token mới nên nếu lộ refresh token thì chưa chắc user sẽ bị chiếm quyền vì cần phải có client ID và secret của bạn nữa. Kể cả trong trường hợp bạn bị lộ cả client ID và secret thì vẫn có thể dễ dàng rotate client secret để vô hiệu hóa secret cũ.
Với access token thì khác, nếu bạn để expiration time dài như 30 ngày hay 1 năm thì khi user bị lộ access token, sẽ không có cách nào để revoke token đó (trừ khi bạn có cơ chế revoke token, mà thường thì k có). Kể cả người dùng có đổi password cũng không thể cứu được, chỉ có xóa tài khoản thôi.
Vậy nên access token nên có expiration time ngắn, và client không nên lưu lại ở đâu cả, chỉ lưu lại refresh token để khi nào cần thì tạo access token mới thôi.
Setting schedule laravel monthlyOn
Ngày không tồn tại sẽ bị bỏ qua nhé bạn.
non-existent times, such as the "missing hours" during the daylight savings time conversion, will never match, causing jobs scheduled during the "missing times" not to be run.
Bạn có thể thêm 1 schedule nữa cho riêng ngày 28-2.
$schedule->command('command:name')->cron('0 0 28 2 *');
Lưu JWT vào localStorage hay Cookie khi authorize requests cho Serverless server?
Có chỗ này mình thấy chắc hơi có chút hiểu lầm đó là cái cookie mà bạn phải set httpOnly
là authorization cookie (chứa JWT) của bạn chứ không phải là cái chứa CSRF token.
Mỗi cơ chế sẽ bảo vệ bạn khỏi một kiểu tấn công khác nhau nên bạn mới cần cả 2 cơ chế để bảo vệ khỏi XSS và CSRF. Để chống XSS thì cookie của bạn phải không thể được đọc bởi code JS, nên set httpOnly
cho authorization cookie sẽ đảm bảo điều kiện này. CSRF attack thì nhắm đến việc cookie của bạn được browser tự động gửi theo request nên phải thêm yêu cầu đó là token phải được submit một cách thủ công (qua form field hoặc thêm vào header bằng JS). Tất nhiên là code JS của bạn phải đọc được CSRF token ở trong cookie thì mới submit nó lên được nên đây không phải là vấn đề bảo mật. Quan trọng là nó không thể đọc được từ một domain khác. Và tất nhiên CSRF token không có tác dụng bảo vệ bạn khỏi XSS nên không thể nói là vì nó không có tác dụng khi bị XSS nên bạn sẽ không dùng nó .
Để cho dễ hình dung thì đây là ví dụ cho kiểu implement này. Bạn có thể thấy viblo_auth
sẽ chứa JWT để authenticate nên sẽ có http_only
còn CSRF_TOKEN
sẽ được đọc bởi JS và submit trong header hoặc form field nên không có http_only
.
Về implement Double Submit Cookie thì thật ra cũng không tốn công gì lắm. Theo mình biết thì nhiều framework phổ biến (Laravel chẳng hạn) có set sẵn cookie CSRF_TOKEN
với request type application/json
cho bạn rồi. Một thư viện HTTP request phổ biến như axios cũng tự động đọc cookie CSRF_TOKEN
và set header x-xsrf-token
cho bạn luôn. Tùy framework mà bạn sử dụng thì có thể bạn chẳng cần làm gì luôn .
Ngoài ra bạn có thể chỉ sử dụng request với content-type application/json
(reject mọi content-type khác) và không set header Access-Control-Allow-Origin: *
. Vì browser sẽ chặn tất cả cross-origin XHR request nên sẽ không có request nào từ domain khác tới được server của bạn, thế là không còn CSRF attack nữa.
Pro Laravel giúp em với ! Câu hỏi về Manually Authenticating trong Laravel
Bạn có thể tự viết 1 cái auth provider như này
<?php
namespace App\Auth;
use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Contracts\Auth\UserProvider as UserProviderInterface;
class UserProvider extends EloquentUserProvider implements UserProviderInterface
{
protected function newModelQuery($model = null)
{
// Thêm đk cho query ở đây hoặc làm gì đó tùy bạn
return parent::newModelQuery($model)->where('role', '!=', 'ABC');
}
}
Xong rồi override cái eloquent provider bằng cái bạn vừa mới thêm ở file AuthServiceProvider.php
như này
public function boot()
{
$this->registerPolicies();
Auth::provider('eloquent', function ($app, array $config) {
return UserProvider(app('Illuminate\Contracts\Hashing\Hasher'), $config['model']);
});
}
hỏi lỗi html dom
Bạn thêm cái này vào thẻ head
là được nhé.
<meta charset="utf-8"/>
Performance của app có bị giảm khi dùng docker?
Bạn dùng Docker for Mac nên nó chạy trong máy ảo, performance sẽ kém hơn, bạn thử chạy trên Linux xem sao. Có thể share code để mình chạy thử được không, mình sẽ share kết quả với bạn.
Em xin hỏi 1 vài vấn đề về gits với ạ.
Bạn push lên gitlab bằng SSH hay HTTP thế, nếu SSH thì chắc là bạn push bằng account ban đầu chứ không phải cái mới thêm vào rồi. Thay đổi name và email trong config chỉ làm thay đổi người commit trong commit history thôi còn account push lên Gitlab thì vẫn là dựa vào SSH key của bạn hoặc là username/password bạn nhập vào lúc push lên.
Còn cái "Create merge request" là để tiện cho người vừa push branch mới lên tạo merge request nhanh thôi còn mọi người đều có thể tạo merge request bằng cách vào link "Merge Request" ở cái sidebar bên trái ấy bạn.
Javascript setInterval() not working in event socket.on()
Vì mỗi giây bạn lại gửi event send_info 1 lần nên cứ 1 giây bạn lại tạo thêm 1 cái interval nữa nên bạn chỉ thấy nó delay 10s ở lần đầu tiên, sau đó là mấy cái interrval được tạo ra lần lượt chạy liên tục.
setInterval
của bạn phải nằm ở ngoài cái event handler và data của mỗi event bạn phải lưu vào đâu đó để xử lý trong mỗi interval. Bạn thử làm thế này xem.
const buffer = [];
socket.on('send_info', function (data) {
buffer.push(data)
// ...
});
setInterval(function () {
const data = buffer.splice(0, buffer.length);
console.log(data);
}, 10000);
Làm sao để mình lưu tên người dùng trên Linux vào một cái array?
Bạn thử làm thế này xem
IFS=' ' read -r -a array <<< "$users"
Làm thế nào để chạy sed script để edit file mà không bị lỗi
Nếu bạn dùng file thì sẽ không có đoạn sed -i ...
nữa mà chỉ có sed script thôi.
Của bạn thì file sẽ như thế này
s/[()]// g
s/[ ]// g
s/[-]// g
s/([0-9][0-9])([0-9])([0-9][0-9][0-9][0-9])([0-9])/\1\4\3\2/
s/8/F/ g
s/6/S/ g
s/7/D/ g
s/9/G/ g
s/4/t/ g
s/2/e/ g
s/3/r/ g
s/0/q/ g
s/1/w/ g
s/5/A/ g
/^[a-z]/aKhangTrann
Gọi API fetch data trong ComponentWillMount hay ComponentDidMount ?
Nếu là cách đây khoảng 1 năm thì bạn mới cần quan tâm đến cái này. Còn bây giờ thì không cần nữa vì phiên bản hiện tại không còn componentWillMount
nữa rồi. Bạn chỉ có thể dùng componentDidMount
thôi. Lý do nó bị bỏ đi là vì tính năng async rendering mới. Bạn có thể xem thêm ở bài này: https://viblo.asia/p/bJzKmMokK9N.
Cũng vì componentWillMount
có vấn đề nên trước đó người ta mới khuyên dùng componentDidMount
. Sau đó thì quyết định bỏ nó luôn để khỏi mất công mọi người thắc mắc.
Tất nhiên nếu bạn đang dùng phiên bản cũ (có vẻ thế) thì bạn có thể dùng cái nào cũng được, không có gì khác nhau cả. Nhưng mà tốt nhất là dùng componentDidMount
để lỡ sau này update lên bản mới thì khỏi mất công sửa lại.
Truyền tham số khi chạy Makefile trên Linux
Bạn có thể làm thế này
hello:
echo $(filter-out $@, $(MAKECMDGOALS))
%:
@:
Đường dẫn tương đối - tuyệt đối khi import trong Reactjs
Câu hỏi của bạn liên quan đến tool create-react-app hơn là React. React là package dùng để render React component. Nó không quan tâm đến việc bạn setup project như thế nào hay bạn làm thế nào để import được component. Đó là việc của các package như Webpack hay Rollup. Vì thế nên mới sinh ra cái tool create-react-app để mọi người nhanh chóng setup project react.
NODE_PATH
thì thật ra vẫn chỉ là 1 workaround cho đến khi create-react-app thực sự support đường dẫn tuyệt đối chứ không phải là một cách hay. Tài liệu chính thức của NodeJS cũng không khuyến khích mọi người dùng NODE_PATH
. Lúc mới support cái này create-react-app cũng gặp phải những vấn đề nghiêm trọng nên cuối cùng hiện tại chỉ support relative path cho NODE_PATH
.
Mục đích ban đầu của NODE_PATH
trong create-react-app là để cho những người có nhu cầu sử dụng create-react-app với monorepo. Kiểu thế này
/packages
- react-app
- components
- sdk
Thì người ta sẽ set NODE_PATH=../components:../sdk
để có thể import file từ folder components và sdk bằng đường dẫn tuyệt đối. Tóm lại là nó dành cho những người có nhu cầu sử dụng chứ không được khuyến khích.
Tuy nhiên các tutorial ở đâu cũng hướng dẫn bạn set NODE_PATH=src
bởi vì nó là 1 use case rất phổ biến. Các framework hay tool tạo boilerplate như Next.js hay vue-cli đều support absolute path nên 1 tool phổ biến như create-react-app cũng không tránh khỏi người dùng đòi hỏi.
Thường thì để cho phép dùng absolute path mọi người sẽ dùng config resolve của webpack. Tác giả của create-react-app thì lại muốn tool này dành cho cả những người chưa biết gì về webpack cũng dùng được nên cách này cuối cùng vẫn không được support.
Trang quá lag khi thực hiện action vì render quá nhiều DOM
Nếu các component trong list của bạn có chiều cao bằng nhau (kiểu table chẳng hạn) thì bạn có thể dùng virtual list rendering, chỉ render những component nào mà bạn đang thấy.
Nếu đang dùng Vue thì bạn thử package này xem https://github.com/Akryum/vue-virtual-scroller
Lỗi chạy npm run build
Nếu bạn đã "nghi" là do version của Node thì ít ra cũng cho mọi người biết là bạn đang dùng version nào, OS nào thì mọi người mới biết đường mà giúp chứ.
Trường hợp của bạn thì có thể là do bạn copy folder node_modules từ đâu đó về thôi chứ lỗi do node version thì nó đã lỗi từ lúc bạn install rồi. Bạn xóa node_modules đi rồi chạy lại npm install
xem có được không. Hoặc là npm rebuild node-sass
thử xem.
MỘT VÀI CÂU HỎI VỀ THƯ VIỆN SIMPLE MDE SỬ DỤNG TRONG VIBLO
SMDE có một option tên là previewRender
để bạn tự dùng renderer mình muốn, không cần tự replace HTML bằng tay. Mặc định thì nó dùng marked. Viblo thì dùng markdown-it. Source code markdown renderer của Viblo thì ở đây https://github.com/viblo-asia/sdk-js/tree/master/src/markdown.
Cái SimpleMDE thì bạn dùng thế này.
const simplemde = new SimpleMDE({
previewRender: content => md.render(content)
})
Còn thêm target="_blank"
vào link thì bạn customize markdown-it như này.
const defaultRenderer = md.renderer.rules.link_open || ((tokens, idx, options, env, self) => self.renderToken(tokens, idx, options));
md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
const token = tokens[idx];
const targetIndex = token.attrIndex('target');
if (targetIndex < 0) {
token.attrPush(['target', '_blank']);
} else {
token.attrs[targetIndex][1] = '_blank;
}
return defaultRenderer(tokens, idx, options, env, self);
};