const sign = require("electron-osx-sign").signAsync;
const notarize = require("electron-notarize").notarize;
-const app = "Crimata.app";
-const dir = `${app}/Contents/Resources/app`;
+const name = "Crimata";
+const dir = `${name}.app/Contents/Resources/app`;
+const registry = "https://gitlab.com/api/v4/projects/25637892/packages/generic/crimata/0.0.1/Crimata.zip";
const runShellCommand = (cmd) => (new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
});
}));
+// /projects/:id/packages/generic/:package_name/:package_version/:file_name?status=:status
+
+
const signConfig = {
- "app": app,
+ "app": name + ".app",
"hardened-runtime": true,
"gatekeeper-assess": false,
"signature-flags": "library",
};
const notarizeConfig = {
- appPath: app,
+ appPath: name + ".app",
appleId: "gundersena@crimata.com",
appBundleId: "com.crimata.CrimataMessenger",
appleIdPassword: process.env["AC_PASSWORD"]
try
{
- console.log("Building...");
- await runShellCommand(`rm -rf ${dir} && mkdir ${dir} && cp -r {package.json,src,node_modules} ${dir}
- `);
+ // console.log("Building...");
+ // await runShellCommand(`rm -rf ${dir} && mkdir ${dir} && cp -r {package.json,src,node_modules} ${dir}
+ // `);
+
+ // console.log("Cleaning...");
+ // await runShellCommand(`xattr -cr ${name}.app`);
- console.log("Cleaning...");
- await runShellCommand(`xattr -cr ${app}`);
+ // console.log("Signing...");
+ // await sign(signConfig);
- console.log("Signing...");
- await sign(signConfig);
+ // console.log("Notarizing...");
+ // await notarize(notarizeConfig);
- console.log("Notarizing...");
- await notarize(notarizeConfig);
+ // console.log("Compressing...");
+ // await runShellCommand(`zip -vr ${name}.zip ${name}.app`);
+
+ console.log("Uploading to Gitlab...");
+ await runShellCommand(`curl --header "PRIVATE-TOKEN: ${process.env["API_TOKEN"]}" --upload-file ${name}.zip "${registry}"`);
}
catch (e)
{
}
})();
+
+
+/**
+ * Copy file from local to remote:
+ *
+ * scp -r Electron.app gundersena@crimata-server:~/Desktop/crimata/website/assets
+ */
\ No newline at end of file
--- /dev/null
+export const isEmail = (value) => {
+ console.log(value);
+ if (!/(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/.test(value)) {
+ return "Not a valid email."
+ }
+}
+
+export const isPassword = (value) => {
+ if (!/^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{6,16}$/.test(value)) {
+ return "Password must have symbol, number, uppercase and be 6-16 length.";
+ }
+}
+
+/**
+ * Name is optional and therefore doesn't return error if no value.
+ */
+export const isName = (value) => {
+ if (value) {
+ if (!/^([a-zA-Z ]){5,30}$/.test(value)) {
+ return "Name must be at least 5 long.";
+ }
+ }
+}
\ No newline at end of file
-const debounce = (fn, delay) => {
+// Basic debounce implentation
+const debounce = (fn, delay) => {
let timeoutId;
-
- const wrapper = (...args) => {
-
- if (timeoutId) {
- clearTimeout(timeoutId);
- }
-
+ return (...args) => {
+ if (timeoutId) clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
fn(...args);
}, delay);
-
}
-
- return wrapper;
}
-
-
-const SmartForm =
+/**
+ * Dynamic form component with auto submission and validation.
+ *
+ * props
+ * .fields => List of field objects
+ * .channel => e.g. "/login"
+ * .modifier => Form description
+ */
+const SmartForm =
{
props: ["fields", "channel", "modifier"],
setup(props)
{
- let logsEl;
-
- const submit = debounce(async (data) => {
-
- let object = {};
- data.forEach(function(value, key){
- object[key] = value;
- });
-
- const err = await window.mainApi.invoke(props.channel, object)
-
- if (err) {
- logsEl.innerText = err;
- logsEl.style.color = "red";
- return;
+ // Error log below form
+ const log = Vue.ref(props.modifier);
+
+ /**
+ * Valid and submit form data to channel.
+ */
+ const submit = async () => {
+
+ // Validate each field
+ for (let field of props.fields) {
+ const error = field.valid(field.value);
+ if (error) return error;
}
- logsEl.style.color = "green";
- logsEl.innerText = props.modifier;
-
- }, 2000);
+ // Reduce fields into the form
+ const form = props.fields.reduce((v, n) => {
+ v[n.name] = n.value;
+ return v;
+ }, {});
- Vue.onMounted(() => {
+ console.log("Submitting =>", form);
+ return await window.mainApi.invoke(props.channel, form);
+ }
- const el = document.getElementById("smart-form");
+ /**
+ * Wrapper for submit that is debounced and updates UI elements
+ */
+ const preSub = debounce(async () => {
- logsEl = el.querySelector(".smart-form-logs");
+ const error = await submit();
- logsEl.innerText = props.modifier;
+ log.value = error ? error : props.modifier
- el.addEventListener("input", () => {
- submit(new FormData(el))
- });
+ }, 2000);
- });
+ return { preSub, log };
},
template: `
- <form id="smart-form" class="smart-form">
+ <form id="smart-form" class="smart-form" v-on:input="preSub">
<div v-for="field in fields" style="display:flex">
- <input type="text" class="text-field"
+ <input type="text" class="text-field"
+ v-model="field.value"
:name="field.name"
- :value="field.value"
:placeholder="field.placeholder"
/>
</div>
- <div class="smart-form-logs"></div>
+ <div class="smart-form-logs">{{ log }}</div>
</form>`
}
export default SmartForm;
+
+
+
import SmartForm from "./form.js";
+import { isEmail, isPassword, isName } from "./control/valid.js";
const Login =
{
setup()
{
- return;
+ return { isEmail, isPassword, isName };
},
template: `
name: 'email',
value: null,
placeholder: 'Email',
+ valid: isEmail
},
{
name: 'password',
value: null,
- placeholder: 'Password'
+ placeholder: 'Password',
+ valid: isPassword
},
{
name: 'name',
value: null,
- placeholder: 'Name'
+ placeholder: 'Name',
+ valid: isName
}]"
:channel="'auth'"
:modifier="'Login or enter name to register.'"
</div>`
}
-export default Login;
\ No newline at end of file
+export default Login;